1 JSON解析代碼
1.1 JSON -> OC
- (void)jsonWithObj {
//NSString *str = @"{\"error\":\"用戶名不存在\"}"; //字典-NSJSONReadingMutableContainers
//NSString *str = @"[\"error\",\"用戶名不存在\"]"; //數(shù)組-NSJSONReadingMutableContainers
//NSString *str = @"\"json string\""; //字符串-NSJSONReadingAllowFragments
//NSString *str = @"false"; //數(shù)字 NSJSONReadingAllowFragments
/*
NSJSONReadingMutableContainers = (1UL << 0), 可變字典和數(shù)組
NSJSONReadingMutableLeaves = (1UL << 1), 內(nèi)部所有字符串都是可變的 ios7之后有問(wèn)題唆香,一般不用
NSJSONReadingFragmentsAllowed = (1UL << 2), 既不是數(shù)組也不是字典黄绩,則必須使用該枚舉值
*/
NSString *str = @"null";
id obj = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
NSLog(@"%@---%@",[obj class],obj);
}
1.2 OC -> JSON
- (void)objToJson {
NSDictionary *dict = @{
@"name":@"xiaoming",
@"age":@"2"
};
NSArray *arr = @[@"name",@"age"];
NSString *str = @"hello world";
// 并不是所有的對(duì)象都可以轉(zhuǎn)換為JSON
/*
- 最外層必須是 NSArray or NSDictionary
- 所有的元素是 NSString, NSNumber, NSArray, NSDictionary, or NSNull
- 字典中所有的key必須是 NSStrings
- NSNumbers 不能無(wú)窮大
*/
BOOL isValid = [NSJSONSerialization isValidJSONObject:str];
NSLog(@"%d",isValid);
if (!isValid) {
return;
}
/*
參數(shù)1:要轉(zhuǎn)換的OC對(duì)象
參數(shù)2:選項(xiàng)NSJSONWritingPrettyPrinted 美化 排版
*/
NSData *data = [NSJSONSerialization dataWithJSONObject:str options:NSJSONWritingPrettyPrinted error:nil];
NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
2 MJExtension
2.1 相關(guān)框架
- Mantal 需要繼承自MIModel
- JSONModel 需要繼承自JSONModel
- MJExtension 不需要繼承瞄勾,無(wú)代碼侵入性
2.2 設(shè)計(jì)和選擇框架時(shí)需要注意的問(wèn)題
- 侵入性
- 易用性廷臼,是否容易上手
- 擴(kuò)展性灶伊,很容易給這個(gè)框架增加新的內(nèi)容
2.3 MJExtension是一套字典和模型之間互相轉(zhuǎn)換的超級(jí)輕量框架
3 XML簡(jiǎn)單介紹
3.1 XML語(yǔ)法 - 元素(Element)
- 一個(gè)元素包括了開(kāi)始標(biāo)簽和結(jié)束標(biāo)簽
- 擁有內(nèi)容的元素:
<video>小黃人</video>
- 沒(méi)有內(nèi)容的元素:
<video></video>
- 沒(méi)有內(nèi)容的元素簡(jiǎn)寫(xiě):
<video/>
- 一個(gè)元素可以嵌套若干個(gè)子元素(不能出現(xiàn)交叉嵌套)
- 規(guī)范的XML文檔最多只有1個(gè)根元素廓潜,其他元素都是根元素的子孫元素
3.2 XML語(yǔ)法 - 元素的注意
- XML中的所有空格和換行丽焊,都會(huì)當(dāng)做具體內(nèi)容處理
- 下面兩個(gè)元素的內(nèi)容是不一樣的
// 第一個(gè)
<video>小黃人<video/>
// 第二個(gè)
<video>
小黃人
<video/>
3.3 XML語(yǔ)法 - 屬性(Attribute)
- 一個(gè)元素可以擁有多個(gè)屬性
<video name="小黃人 第01部" length="30" />
video元素?fù)碛?name
和length
兩個(gè)屬性
屬性值必須用雙引號(hào)"" 或者 單引號(hào) '' 擴(kuò)住
- 實(shí)際上妹窖,屬性表示的信息也可以用子元素來(lái)表示啊奄,不如
<video>
<name>小黃人 第01部</name>
<length>30</length>
</video>
3.4 XML解析
- 想要從XML中提取有用的信息渐苏,必須得學(xué)會(huì)解析XML
1)提取name
元素里面的內(nèi)容
<name>小黃人 第01部</name>
2)提取video
元素中name
和length
屬性的值
<video name="小黃人 第01部" length="30" /> - XML的解析方式有2種
1)DOM:一次性將整個(gè)XML文檔加載進(jìn)內(nèi)存,比較適合解析小文件
2)SAX:從根元素開(kāi)始菇夸,按順序一個(gè)元素一個(gè)元素往下解析琼富,比較適合解析大文件
3.5 iOS中的XML解析
- 在iOS中,解析XML的手段很多
1)蘋(píng)果原生:NSXMLParser:SAX方式解析庄新,使用簡(jiǎn)單
2)第三方框架
libxml2:純c語(yǔ)言鞠眉,默認(rèn)包含在iOS SDK中,同時(shí)支持DOM和SAX方式解析
GDataXML:DOM方式解析择诈,由Google開(kāi)發(fā)械蹋,基于libxml2 - XML解析方式的選擇建議
1)大文件:NSXMLParser、libxml2
2)小文件:GDataXML羞芍、NSXMLParser哗戈、libxml2
4 NSXMLParser解析XML:SAX
- (void)xml {
NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Provinces.xml" ofType:nil]];
//1 創(chuàng)建解析器
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
//2 設(shè)置代理
parser.delegate = self;
//3 解析文件
[parser parse]; // 阻塞
}
#pragma mark - NSXMLParserDelegate
//1 開(kāi)始解析xml文檔
- (void)parserDidStartDocument:(NSXMLParser *)parser {
NSLog(@"%s",__func__);
}
//2 開(kāi)始解析xml某個(gè)元素
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
if ([elementName isEqualToString:@"Provinces"]) {
return;
}
NSLog(@"%@---%@",elementName,attributeDict);
}
//3 xml某個(gè)元素解析完畢
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(@"%@元素解析完畢",elementName);
}
//4 xml文檔解析完畢
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(@"%s",__func__);
}
5 GDataXML解析XML:DOM
5.1 GDataXML配置
- GDataXML基于libxml2庫(kù),得做以下配置
導(dǎo)入libxml2
庫(kù) - 設(shè)置
libxml2
的頭文件搜索路徑(為了能找到libxml2庫(kù)的所有頭文件)
在Head Search Path中加入/usr/include/libxml2 - 設(shè)置鏈接參數(shù)(自動(dòng)鏈接libxml2庫(kù))
在Other Linker Flags中加入-lmxl2 - mrc文件編譯方式
-fno-objc-arc
- (void)xml {
NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Provinces.xml" ofType:nil]];
//1 加載xml文檔
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:kNilOptions error:nil];
//2 拿到根元素荷科,得到元素內(nèi)部所有名稱為video的子孫元素
NSArray *elements = [doc.rootElement elementsForName:@"Province"];
//3 遍歷
for (GDataXMLElement *element in elements) {
ProviceModel *model = [[ProviceModel alloc] init];
model.provinceName = [element attributeForName:@"ProvinceName"].stringValue;
[self.dataArray addObject:model];
}
NSLog(@"%zd",self.dataArray.count);
}
- (NSMutableArray *)dataArray {
if (!_dataArray) {
_dataArray = [NSMutableArray array];
}
return _dataArray;
}
6 多值參數(shù)和中文輸出
6.1 多值參數(shù)
htpp://120.25.227.189:3244/weather?place=Sichuan&place=Beijing"
6.2 中文輸出
#import <Foundation/Foundation.h>
@implementation NSDictionary (Log)
//重寫(xiě)系統(tǒng)的方法控制輸出
-(NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
{
// return @"你大爺是你大姐";
NSMutableString *string = [NSMutableString string];
//{}
[string appendString:@"{"];
//拼接key--value
[self enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
[string appendFormat:@"%@:",key];
[string appendFormat:@"%@,",obj];
}];
[string appendString:@"}"];
//刪除逗號(hào)
//從后往前搜索 得到的是搜索到的第一個(gè)符號(hào)的位置
NSRange range = [string rangeOfString:@"," options:NSBackwardsSearch];
if (range.location != NSNotFound) {
[string deleteCharactersInRange:range];
}
return string;
}
@end
@implementation NSArray (Log)
//重寫(xiě)系統(tǒng)的方法控制輸出
-(NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
{
// return @"你大爺是你大姐";
NSMutableString *string = [NSMutableString string];
//{}
[string appendString:@"["];
//拼接obj
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[string appendFormat:@"%@,\n",obj];
}];
[string appendString:@"]"];
//刪除逗號(hào)
//從后往前搜索 得到的是搜索到的第一個(gè)符號(hào)的位置
NSRange range = [string rangeOfString:@"," options:NSBackwardsSearch];
if (range.location != NSNotFound) {
[string deleteCharactersInRange:range];
}
return string;
}
7 NSURLConnection實(shí)現(xiàn)大文件下載
下載文件的時(shí)候唯咬,如果一次性下載下來(lái)纱注,保存到內(nèi)存,會(huì)導(dǎo)致內(nèi)存飆升胆胰。
應(yīng)該使用代理狞贱,將文件保存到本地。
-#import "ViewController.h"
@interface ViewController ()<NSURLConnectionDataDelegate>
@property (weak, nonatomic) IBOutlet UIProgressView *progress;
@property (assign, nonatomic) NSInteger currentSize;
@property (assign, nonatomic) NSInteger totalSize;
@property (strong, nonatomic) NSURLConnection *connection;
@property (strong, nonatomic) NSFileHandle *handle;
@property (strong, nonatomic) NSString *fullPath;
@end
@implementation ViewController
- (IBAction)beginToDownLoad:(id)sender {
[self download];
}
- (IBAction)stopToDownload:(id)sender {
// 取消下載
[self.connection cancel];
NSLog(@"+++++++cancle");
}
//異步請(qǐng)求:代理方式
- (void)download {
//1 url地址
NSURL *url = [NSURL URLWithString:@"http://www.hitow.net/data/attachment/album/201612/10/205628nppuzll3137siny2.jpg"];
//2 請(qǐng)求請(qǐng)求對(duì)象
// 請(qǐng)求頭不需要設(shè)置(默認(rèn)請(qǐng)求頭)
NSMutableURLRequest *requet = [NSMutableURLRequest requestWithURL:url];
// 設(shè)置請(qǐng)求頭:告訴服務(wù)器請(qǐng)求一部分?jǐn)?shù)據(jù)range
/*
bytes=0-100 請(qǐng)求前100個(gè)字節(jié)
bytes=-100 請(qǐng)求最后100個(gè)字節(jié)
bytes=100- 請(qǐng)求100之后的所有字節(jié)
*/
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
[requet setValue:range forHTTPHeaderField:@"Range"];
//3 發(fā)送異步請(qǐng)求
self.connection = [[NSURLConnection alloc] initWithRequest:requet delegate:self];
}
#pragma mark - NSURLConnectionDataDelegate
// 1 客戶端收到服務(wù)端響應(yīng)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(@"%s",__func__);
//expectedContentLength:當(dāng)前請(qǐng)求的數(shù)據(jù)大小蜀涨,但不一定是整個(gè)下載文件的大小
self.totalSize = response.expectedContentLength + self.currentSize;
//獲取文件下載路徑
NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
//使用服務(wù)端返回的建議文件名字
NSString *fileName = response.suggestedFilename;
//文件全路徑
self.fullPath = [filePath stringByAppendingPathComponent:fileName];
//創(chuàng)建本地空文件
[[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
//創(chuàng)建文件句柄
self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
}
//2 客戶端接收到服務(wù)端數(shù)據(jù)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//移動(dòng)文件句柄到文件的末尾
[self.handle seekToEndOfFile];
//寫(xiě)入數(shù)據(jù)
[self.handle writeData:data];
// 獲取當(dāng)前下載文件的進(jìn)度
self.currentSize += data.length;
CGFloat percent = (self.currentSize * 1.0)/self.totalSize;
self.progress.progress = percent;
NSLog(@"%f",percent);
}
//3 客戶端數(shù)據(jù)請(qǐng)求失敗
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"%s",__func__);
}
//4 客戶度數(shù)據(jù)請(qǐng)求完畢
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//關(guān)閉文件句柄
[self.handle closeFile];
self.handle = nil;
NSLog(@"file download over");
}
8 輸出流
輸出流的方式和文件句柄類似瞎嬉,都是將從服務(wù)端獲取的數(shù)據(jù)保存到指定的本地沙盒路徑下。
#import "ViewController.h"
@interface ViewController ()<NSURLConnectionDataDelegate>
@property (weak, nonatomic) IBOutlet UIProgressView *progress;
@property (assign, nonatomic) NSInteger currentSize;
@property (assign, nonatomic) NSInteger totalSize;
@property (strong, nonatomic) NSURLConnection *connection;
// 文件句柄
@property (strong, nonatomic) NSFileHandle *handle;
// 輸出流
@property (strong, nonatomic) NSOutputStream *stream;
// 文件路徑
@property (strong, nonatomic) NSString *fullPath;
@end
@implementation ViewController
- (IBAction)beginToDownLoad:(id)sender {
[self download];
}
- (IBAction)stopToDownload:(id)sender {
// 取消下載
[self.connection cancel];
NSLog(@"+++++++cancle");
}
//異步請(qǐng)求:代理方式
- (void)download {
//1 url地址
NSURL *url = [NSURL URLWithString:@"http://www.hitow.net/data/attachment/album/201612/10/205628nppuzll3137siny2.jpg"];
//2 請(qǐng)求請(qǐng)求對(duì)象
// 請(qǐng)求頭不需要設(shè)置(默認(rèn)請(qǐng)求頭)
NSMutableURLRequest *requet = [NSMutableURLRequest requestWithURL:url];
// 設(shè)置請(qǐng)求頭:告訴服務(wù)器請(qǐng)求一部分?jǐn)?shù)據(jù)range
/*
bytes=0-100 請(qǐng)求前100個(gè)字節(jié)
bytes=-100 請(qǐng)求最后100個(gè)字節(jié)
bytes=100- 請(qǐng)求100之后的所有字節(jié)
*/
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
[requet setValue:range forHTTPHeaderField:@"Range"];
//3 發(fā)送異步請(qǐng)求
self.connection = [[NSURLConnection alloc] initWithRequest:requet delegate:self];
}
#pragma mark - NSURLConnectionDataDelegate
// 1 客戶端收到服務(wù)端響應(yīng)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(@"%s",__func__);
//expectedContentLength:當(dāng)前請(qǐng)求的數(shù)據(jù)大小勉盅,但不一定是整個(gè)下載文件的大小
self.totalSize = response.expectedContentLength + self.currentSize;
//獲取文件下載路徑
NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
//使用服務(wù)端返回的建議文件名字
NSString *fileName = response.suggestedFilename;
//文件全路徑
self.fullPath = [filePath stringByAppendingPathComponent:fileName];
//創(chuàng)建輸出流
/*
參數(shù)1:文件路徑
參數(shù)2:是否追加
特殊:如果本地沒(méi)有該文件佑颇,會(huì)自動(dòng)創(chuàng)建一個(gè)空的文件
*/
self.stream = [NSOutputStream outputStreamToFileAtPath:self.fullPath append:YES];
// 打開(kāi)輸出流
[self.stream open];
}
//2 客戶端接收到服務(wù)端數(shù)據(jù)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//保存數(shù)據(jù)到指定的路徑
[self.stream write:data.bytes maxLength:data.length];
// 獲取當(dāng)前下載文件的進(jìn)度
self.currentSize += data.length;
CGFloat percent = (self.currentSize * 1.0)/self.totalSize;
self.progress.progress = percent;
NSLog(@"%f",percent);
}
//3 客戶端數(shù)據(jù)請(qǐng)求失敗
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"%s",__func__);
}
//4 客戶度數(shù)據(jù)請(qǐng)求完畢
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//關(guān)閉輸出流
[self.stream close];
self.stream = nil;
NSLog(@"file download over");
}
9 NSURLConnection實(shí)現(xiàn)文件上傳
//文件上傳步驟
/*
1.設(shè)置請(qǐng)求頭
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryjv0UfA04ED44AhWx
2.按照固定的格式拼接請(qǐng)求體的數(shù)據(jù)
------WebKitFormBoundaryjv0UfA04ED44AhWx
Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
Content-Type: image/png
------WebKitFormBoundaryjv0UfA04ED44AhWx
Content-Disposition: form-data; name="username"
123456
------WebKitFormBoundaryjv0UfA04ED44AhWx--
*/
//拼接請(qǐng)求體的數(shù)據(jù)格式
/*
拼接請(qǐng)求體
分隔符:----WebKitFormBoundaryjv0UfA04ED44AhWx
1)文件參數(shù)
--分隔符
Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
Content-Type: image/png(MIMEType:大類型/小類型)
空行
文件參數(shù)
2)非文件參數(shù)
--分隔符
Content-Disposition: form-data; name="username"
空行
123456
3)結(jié)尾標(biāo)識(shí)
--分隔符--
*/
#import "ViewController.h"
#define Kboundary @"----WebKitFormBoundaryjv0UfA04ED44AhWx"
#define KNewLine [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]
@interface ViewController ()
@end
@implementation ViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self upload];
}
-(void)upload
{
//1.確定請(qǐng)求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
//2.創(chuàng)建可變的請(qǐng)求對(duì)象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//3.設(shè)置請(qǐng)求方法
request.HTTPMethod = @"POST";
//4.設(shè)置請(qǐng)求頭信息
//Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryjv0UfA04ED44AhWx
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary] forHTTPHeaderField:@"Content-Type"];
//5.拼接請(qǐng)求體數(shù)據(jù)
NSMutableData *fileData = [NSMutableData data];
//5.1 文件參數(shù)
/*
--分隔符
Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
Content-Type: image/png(MIMEType:大類型/小類型)
空行
文件參數(shù)
*/
[fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
//name:file 服務(wù)器規(guī)定的參數(shù)
//filename:Snip20160225_341.png 文件保存到服務(wù)器上面的名稱
//Content-Type:文件的類型
[fileData appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"Snip20160225_341.png\"" dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
[fileData appendData:[@"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
[fileData appendData:KNewLine];
UIImage *image = [UIImage imageNamed:@"Snip20160225_341"];
//UIImage --->NSData
NSData *imageData = UIImagePNGRepresentation(image);
[fileData appendData:imageData];
[fileData appendData:KNewLine];
//5.2 非文件參數(shù)
/*
--分隔符
Content-Disposition: form-data; name="username"
空行
123456
*/
[fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
[fileData appendData:[@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
[fileData appendData:KNewLine];
[fileData appendData:[@"123456" dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
//5.3 結(jié)尾標(biāo)識(shí)
/*
--分隔符--
*/
[fileData appendData:[[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
//6.設(shè)置請(qǐng)求體
request.HTTPBody = fileData;
//7.發(fā)送請(qǐng)求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
//8.解析數(shù)據(jù)
NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}];
}