序言:
以下实验效果会采用简单的方式呈现,读者可根据自身情况修改实验代码
#####一、JSON解析 这里,我们需要先分析数据再做解析操作!
1.准备的数据:在Safari浏览器访问https://www.crios.cn/test.json 2.效果图如下
打开xcode->新建项目->新建Person模型装载json数据
// 代码如下// 以下代码意义是根据数据来创建变量的#import@interface Person : NSObject@property (copy, nonatomic) NSString *username;@property (strong, nonatomic) NSNumber *age;@property (strong, nonatomic) NSNumber *id;@end复制代码
回到ViewContorller.m文件,添加以下代码
/* 在头部导入Person类// Model#import "Person.h"*/ // 1.创建url NSURL *url = [NSURL URLWithString:@"https://www.crios.cn/test.json"]; // 2.创建请求 NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:10.0]; // 3.创建NSURLSession NSURLSession *session = [NSURLSession sharedSession]; // 4.创建NSURLSessionDataTask NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (!error) { NSArray *jsons = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; NSMutableArray *results = [NSMutableArray array]; for (NSDictionary *dic in jsons) { Person *person = [[Person alloc] init]; [person setValuesForKeysWithDictionary:dic]; [results addObject:person]; } NSLog(@"结果:%@", results); } else { NSLog(@"错误提示:%@",error); } }]; // 5.开启任务(如果任务在挂起状态,这里会重新开启任务) [dataTask resume];复制代码
setValuesForKeysWithDictionary意义: dic中的key会找Person类中的变量,一一对应,再将key对应的value赋值过去
打印效果:
上面无法打印模型的变量值,我们可在Person.m文件中添加以下代码:
- (NSString *)description { return [NSString stringWithFormat:@"<%@:%p>{id:%@,name:%@,age:%@}",self.class,self,_id, _username, _age]; }复制代码
输出效果
#####第一问,我们已设定好Person类中的变量,但我们定义好的Person类与服务器返回的数据不一致会出现何种情况,此时怎么办?
程序直接奔溃
莫慌,直接在Person.m文件中添加如下代码
// 代码块暂时不需要其他操作,可空着- (void)setValue:(id)value forUndefinedKey:(NSString *)key { }复制代码
程序正常跑起来了。 #####接着来,第二问,服务器返回的数据,有我们OC语言的关键字,赋值操作会出现一些无法预测的问题,这可咋办呢?
解决这个问题首先先在Person.h文件中修改代码
@property (copy, nonatomic) NSString *username;//@property (strong, nonatomic) NSNumber *age;// 将关键字修改成我们想要的模样@property (strong, nonatomic) NSNumber *ID;复制代码
其次在Person.m文件中添加如下代码
- (void)setValue:(id)value forUndefinedKey:(NSString *)key { if ([key isEqualToString:@"id"]) { self.ID = value; } }复制代码
实验效果跟预期一样。成功了。?
#####第三问,我们打印的数组中,出现的中文为乱码,这可咋办呢?
新建NSArray Category
在NSArray+Log.m文件中添加以下代码
// 实际代码看这里,以下代码意义不解释,相信大家都看得懂- (NSString *)descriptionWithLocale:(id)locale { NSMutableString *resultStr = [NSMutableString stringWithString:@"??(\n"]; [self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [resultStr appendFormat:@"\t%@\n",obj]; }]; [resultStr appendFormat:@")\n"]; return resultStr;}复制代码
结果输出:
#####二、XML解析 XML: XML是一种可扩展"标记"语言,特点是阅读方便,美观大方。 解析方式:
方式 | 介绍 | 特点 |
---|---|---|
DOM | MAC提供的解析方法,iOS中无法直接使用 | 1.内存开销大 2.可读可写3.将数据以树形结构加载到内存 |
SAX | 适用于iOS的解析方式 | 1.内存开销小2.只读3.速度快4.从上到下,顺序解析的过程 |
行,我们来做实验。 1)同样的,我们也需要分析数据再做解析操作!
1.准备的数据:在谷歌浏览器访问http://www.crios.cn/persons.xml (数据也可从其他地方来,道理是一样的) 2.效果图如下
2)新建Person类,来装载数据,看了前面的json解析之后,这里会更容易明白。
Person.h文件
@property (strong, nonatomic)NSNumber *personId;@property (copy, nonatomic)NSString *height;@property (copy, nonatomic)NSString *age;@property (copy, nonatomic)NSString *name;@property (copy, nonatomic)NSString *sex;@property (copy, nonatomic)NSString *desc;复制代码
Person.m文件
- (NSString *)description { return [NSString stringWithFormat:@"<%@:%p>{videoID:%@,name:%@,age:%@,height:%@,sex:%@,desc:%@}",[self class],self,self.personId,self.name,self.age,self.height,self.sex,self.desc]; }- (void)setValue:(id)value forUndefinedKey:(NSString *)key { // 这里代码可空着,主要意义是防止服务器返回的数据与我们创建的Model类对应不上}复制代码
4)ViewController.m文件
// 1.导入Person 类#import "Person.h"// 2.遵守代理协议@interface ViewController ()// 3.创建可变数组@property (strong, nonatomic) NSMutableArray *persons;// 4.创建可变字符串@property (strong , nonatomic) NSMutableString *elementStr;// 5.当前解析的节点模型@property (strong, nonatomic) Person *currentPerson;@end@implementation ViewController// MARK: 懒加载- (NSMutableArray *)persons { if (!_ persons) { _ persons = [[NSMutableArray alloc] init]; } return _ persons;}- (NSMutableString *)elementStr { if (!_elementStr) { _elementStr = [[NSMutableString alloc] init]; } return _elementStr;}@end复制代码
- 请求数据
//1.url NSURL *url = [NSURL URLWithString:@"http://www.crios.cn/persons.xml"]; // 2.创建请求 NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:10.0]; // 3.创建NSURLSession NSURLSession *session = [NSURLSession sharedSession]; // 4.创建NSURLSessionDataTask NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (!error) { // XML解析 NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:data]; // 设置代理 xmlParser.delegate = self; //解析器解析 [xmlParser parse]; } }]; // 5.开启任务(如果任务在挂起状态,这里会重新开启任务) [dataTask resume];复制代码
3)补充说明这里采用苹果原生NSXMLParser类来进行解析,主要通过6种代理方法来进行操作
// 1.打开文档- (void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"1.开始文档"); //1.清空数组 [self.persons removeAllObjects];}// 2.开始节点- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary*)attributeDict { if ([elementName isEqualToString:@"person"]) { //1.新建模型 self.currentPerson = [[Person alloc] init]; //2设置personID的属性 self.currentPerson.personId = @([attributeDict[@"personId"] intValue]); }}// 3.发现节点内容- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { [self.elementStr appendString:string];}// 4.结束节点- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { if ([elementName isEqualToString:@"person"]) { [self.persons addObject:self.currentPerson]; } else if (![elementName isEqualToString:@"persons"]) { [self.currentPerson setValue:self.elementStr forKey:elementName]; } //清空字符串 [self.elementStr setString:@""];}// 5.结束解析- (void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"结果:%@",self.persons);}// 6.错误处理- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"错误描述:%@",parseError.description);}复制代码
#####总结: ##### 实验结束,解析JSON这里为了便捷展示采用苹果原生NSJSONSerialization
类解析。简单粗暴。 ##### 网络请求不用老方法:NSURLConnection中的 sendAsynchronousRequest
,直接采用NSURLSession。 ##### 最后,模型的赋值可采用Runtime机制,效率会更高,这里不多讲,后面会专门写Runtime文章