NSURLConnection
NSURLSession
普通网络请求
JSON数据解析
JSON序列化
数据解析
解析规则:
具体示例
重写setValue: forUndefinedKey:方法
重写setNilValueForKey:方法
解析的几种方式
KVC
网络类的基本封装(非终极版)
SDWebImage
MJRefresh
NSURLConnection
这种网络请求方式, 在iOS9已经被彻底抛弃了. 官方推荐使用功能更加强大完善的NSURLSession.
NSURLSession
iOS7之后生效的原生网络请求类, 取代之前的NSURLSession
普通网络请求
NSURLSession*session = [NSURLSessionsharedSession];
NSURLSessionDataTask*task = [session dataTaskWithURL:[NSURLURLWithString:kHeroPath] completionHandler:^(NSData* _Nullable data,NSURLResponse* _Nullable response,NSError* _Nullable error) {
/*data参数就是从网络上下载下来的数据
这个数据是服务器把 字典/数组 根据JSON协议编码以后生成的. 拿到JSON数据以后, 我们要反编码 回到字典或者数组
*/
//因为根据返回值类型, 可以看到是字典类型的
//Serialization:序列化
//参数2:options 代表当前data原始数据是什么类型
//MutableContainers:代表原始数据是数组/字典
NSError*err =nil;
NSDictionary*responseObj = [NSJSONSerializationJSONObjectWithData:data options:NSJSONReadingMutableContainerserror:&err];
NSLog(@"responseObj %@", responseObj);
self.parse= [HerosParse parse:responseObj];
NSLog(@"");
//数据获取完成以后, 要刷新界面. 网络请求是子线程, 刷新界面要回归主线程
[[NSOperationQueuemainQueue] addOperationWithBlock:^{
[_tableView reloadData];//刷新界面
}];
}];
//开始发送请求
[task resume];
JSON数据解析
JSON序列化
数据从服务器传递到终端, 数据通常是字典或者数组类型, 当传递这些类型时,
需要通过一定的规则把数组/字典转化为字符串的形式, 这个规则称为Json.
当终端获取到这些字符串时, 需要再重新转换为数据原本的样式.
我们称这种 字典/数组 和 JSON样式字符串 之间的转化, 为JSON序列化
//把JSON的数据 转换为 原始状态
NSError*err =nil;
NSDictionary*responseObj = [NSJSONSerializationJSONObjectWithData:data options:NSJSONReadingMutableContainerserror:&err];
//参数2 代表原始状态的数据类型
typedefNS_OPTIONS(NSUInteger,NSJSONReadingOptions) {
NSJSONReadingMutableContainers= (1UL <<0),//可变数组/字典
NSJSONReadingMutableLeaves= (1UL <<1),//可变字符串
NSJSONReadingAllowFragments= (1UL <<2)//允许JSON字符串最外层既不是NSArray也不是NSDictionary,但必须是有效的JSON Fragment
}NS_ENUM_AVAILABLE(10_7,5_0);
//把OC类型 转为 JSON数据
[NSJSONSerializationdataWithJSONObject:responseObj options:NSJSONWritingPrettyPrintederror:nil];
数据解析
在使用字典时, 要经常使用字符串的key来获取字典中的value, 这样用起来很麻烦.
因为字符串没有代码提示, 容易犯错. 这时候就自然有了一个需求, 要把字典转化为对象来使用.
我们称这种把字典转化为类的方式为数据解析.
解析规则:
遇到字典则新建类型
建完类型以后 立刻把所有的键对应的属性声明
每个类型都需要一个解析 类方法
对于数组类型的属性, 要标记它的内容, 通过@class引入类型
解析方法的实现顺序, 由底层向表层实现
具体示例
//对于下方字典的解析操作
{
"all": [
{
"cnName":"俄洛伊",
"enName":"Illaoi",
"location":"上单",
"price":"6300,4500",
"rating":"8,6,3,4",
"tags":"fighter",
"title":"海兽祭司"
}]
}
//解析类
@classHerosAllParse;
@interfaceHerosParse:NSObject
@property(nonatomic)NSArray *all;
+ (instancetype)parse:(NSDictionary*)dic;
@end
@interfaceHerosAllParse:NSObject
@property(nonatomic)NSString*cnName;
@property(nonatomic)NSString*enName;
@property(nonatomic)NSString*location;
@property(nonatomic)NSString*price;
@property(nonatomic)NSString*rating;
@property(nonatomic)NSString*tags;
@property(nonatomic)NSString*title;
+ (instancetype)parse:(NSDictionary*)dic;
@end
@implementationHerosParse
+ (instancetype)parse:(NSDictionary*)dic{
NSMutableArray*arr = [NSMutableArraynew];
NSArray*array = dic[@"all"];
for(NSDictionary*dicinarray) {
[arr addObject:[HerosAllParse parse:dic]];
}
//把内容是字典的数组 替换为 内容是**类型的数组
NSMutableDictionary*mutableDic = [NSMutableDictionarydictionaryWithDictionary:dic];
[mutableDic setObject:arr forKey:@"all"];
idobj = [selfnew];
[obj setValuesForKeysWithDictionary:mutableDic];
returnobj;
}
- (void)setValue:(id)value forUndefinedKey:(NSString*)key{}
- (void)setNilValueForKey:(NSString*)key{}
@end
@implementationHerosAllParse
+ (instancetype)parse:(NSDictionary*)dic{
idobj = [selfnew];
[obj setValuesForKeysWithDictionary:dic];
returnobj;
}
- (void)setValue:(id)value forUndefinedKey:(NSString*)key{}
- (void)setNilValueForKey:(NSString*)key{}
@end
重写setValue: forUndefinedKey:方法
通过重写此方法, 可以防止对不存在的key使用KVC方式复制, 而导致的崩溃现象
重写setNilValueForKey:方法
通过重写此方法, 可以防止对key赋nil值, 导致的崩溃现象
解析的几种方式
//通过KVC方式赋值, 可以有效减少代码量
+ (HeroParse *)parse:(NSDictionary *)dic{
HeroParse *parse = [self new];
//自动把字典的键值对应放到属性中
[parsesetValuesForKeysWithDictionary:dic];
//遍历字典enumerate: 遍历,枚举
/*
[dic enumerateKeysAndObjectsUsingBlock:^(id_Nonnull key, id_Nonnull obj, BOOL * _Nonnull stop) {
[parsesetValue:objforKey:key];
}];
*/
//通过KVC的方式对属性进行赋值
//[parsesetValue:dic[@"cnName"]forKey:@"cnName"];
//parse.cnName = dic[@"cnName"];
/*
parse.enName = dic[@"enName"];
parse.location = dic[@"location"];
parse.price = dic[@"price"];
parse.rating = dic[@"rating"];
parse.tags = dic[@"tags"];
parse.title = dic[@"title"];
*/
returnparse;
}
KVC
除了一般的赋值和取值的方法,我们还可以用Key-Value-Coding(KVC)键值编码来访问你要存取的类的属性。
例如:
@interfaceStudent:NSObject
@propertyNSString*name;
@end
Student *stu = [Student new];
//这是使用getter和setter方法来对值进行读取和写入操作
stu.name=@"小明";
NSLog(@"%@", stu.name);
//KVC方式
[stu setValue:@"小明"forKey:@"name"];
NSLog(@"%@", [stu valueForKey:@"name"]);
网络类的基本封装(非终极版)
根据程序的设计原则: MVC, 解耦和
ViewController应该只负责把数据呈现在View上
所以要把网络请求的逻辑独立放在外部
@interfaceServerNetwork:NSObject
+ (id)getServerListCompletionHandle:(void(^)(idmodel,NSError*error))completionHandle;
@end
@implementation
+ (id)getServerListCompletionHandle:(void(^)(id,NSError*))completionHandle{
NSString*path =@"http://lolbox.duowan.com/phone/apiServers.php?v=77&OSType=iOS8.2&versionName=2.1.7";
NSURLSessionDataTask*task = [[NSURLSessionsharedSession] dataTaskWithURL:[NSURLURLWithString:path] completionHandler:^(NSData* _Nullable data,NSURLResponse* _Nullable response,NSError* _Nullable error) {
if(error) {//请求操作出现问题
completionHandle(nil, error);
return;
}
NSError*err =nil;
NSArray*arr = [NSJSONSerializationJSONObjectWithData:data options:NSJSONReadingMutableContainerserror:&err];
if(err) {//JSON解析出错了
completionHandle(nil, err);
return;
}
//开始解析
NSMutableArray*mulArr = [NSMutableArraynew];
for(NSDictionary*dicinarr) {
[mulArr addObject:[ServerParse parse:dic]];
}
//为了安全考虑,返回的数组应该是不可变数组
completionHandle([mulArrcopy],nil);
}];
[task resume];
returntask;
}
@end
SDWebImage
github上目前最好的为原生控件增加网络图片功能的第三方类库.SDWebImage
//专门用于为图片控件添加网络操作的Category
#import"UIImageView+WebCache.h"
//SDWebImage
UIImageView*iconIV = [UIImageViewnew];
NSString*path = [NSStringstringWithFormat:@"http://img.lolbox.duowan.com/champions/%@_120x120.jpg", _heroInfo.enName];
//SDWebImage让UIImageView类型拥有了网络功能
[iconIV sd_setImageWithURL:[NSURLURLWithString:path]];
MJRefresh
国人编写的, 为滚动视图添加刷新UI的第三方框架.MJRefresh
官方有详细的中文文档, 自行查看
#import"MJRefresh.h"//上下拉动的UI显示
//为表格添加下拉刷新头部UI控件
_tableView.mj_header= [MJRefreshNormalHeader headerWithRefreshingBlock:^{
[ServerNetwork getServerListCompletionHandle:^(idmodel,NSError*error) {
if(error) {
NSLog(@"error %@", error);
}else{
self.servers= model;
//刷新界面要在主线程中做
[[NSOperationQueuemainQueue] addOperationWithBlock:^{
[_tableView reloadData];
}];
}
[[NSOperationQueuemainQueue] addOperationWithBlock:^{
//结束刷新操作
[_tableView.mj_headerendRefreshing];
}];
}];
}];
//刚运行时,应该刷新一次
[_tableView.mj_headerbeginRefreshing];