iOS网络相关

网络,常常和多线程搞混,以前想复杂了,其实采用最简洁的使用方式才是推荐的方式。

历史

大约在2012年左右的样子,关于iOS的网络第三方库,一般有三种观点

asi-http-request

MKNetworkKit

AFNetworking

当时的普遍说法是ASI已经停止更新;AF比较小,使用比较简单;MKASI的效率,接口和AF一样好用。
当时我所在的项目组选用的是MK,当然现在接触的项目,网络库基本上选择AFNetworking。这个基本上已经成为事实上的标准了。

另外一个比较相关的内容是图片的上传和下载。AFNetworking其实是有图片上传和下载相关的功能的,但是实际接触的项目中用的非常少。SDWebImage基本上成为图片上传下载的事实标准。

学习资料

iOS关于网络的API,一开始是NSURLConnection,当前,基本上已经过渡到NSURLSession,下面几篇文章都是不错的学习资料

iOS开发网络篇—发送GET和POST请求(使用NSURLSession)

NSURLSession使用说明及后台工作流程分析

iOS开发 GET、POST请求方法:NSURLSession篇

让iOS项目允许使用http协议请求

数据业务

如果采用AFNetworking的话,按照网上的教程来,比如iOS开发——AFNetworking框架使用详解,相对比较省心。
如果想自己尝试写的话,那么就要多考虑一些了。
数据业务应该是APP中使用最多的场景:
(1)从后台拿数据,显示页面;
(2)提交用户数据,提交后台处理,响应之后更新页面。

采用GET还是POST,或者两者都有?

  • 从后台拿数据,显示页面
    对于这种场景,GET还是有优势的。不需要用户提供数据,仅仅是访问后台,像普通的浏览器访问网站一样,用GET完全满足要求。
    GET访问,可以做缓存,加快访问速度。
    GETNSURLSession的默认方式,只要有URL就可以,甚至连URLRequest都不需要。
- (void)getWithUrl {
    //1.确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
    
    //2.获得会话对象
    NSURLSession *session = [NSURLSession sharedSession];
    
    //3.根据会话对象创建一个Task(发送请求)
    /*
     第一个参数:请求路径
     第二个参数:completionHandler回调(请求完成【成功|失败】的回调)
               data:响应体信息(期望的数据)
               response:响应头信息,主要是对服务器端的描述
               error:错误信息,如果请求失败,则error有值
     注意:
        1)该方法内部会自动将请求路径包装成一个请求对象,该请求对象默认包含了请求头信息和请求方法(GET)
        2)如果要发送的是POST请求,则不能使用该方法
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //5.解析数据
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
        NSLog(@"%@",dict);
        
    }];
    
    //4.执行任务
    [dataTask resume];
}
  • 提交用户数据,提交后台处理,响应之后更新页面
    这种场景,GET就无能为力了,需要用到POST方式;
    仅仅URL不够,需要用到URLRequest
    用户数据,放在URLRequestHTTPBody之中,NSStringNSData,使用NSUTF8StringEncoding编码
    URLRequest的HTTPBody属性,需要设置为@"POST"

  • URLRequest的头部,一般都需要加一些特殊信息,用来验证一个可信的链接。比如版本号,token,sign,deviceID等等

  • POST是无法避免的,而GET方式可以采用和POST一样的方式实现,也就是使用URLRequest来实现。或者说,GET方式能做的事可以用POST方式来取代。

- (void)getWithURLRequest {
    //对请求路径的说明
    //http://120.25.226.186:32812/login?username=520it&pwd=520&type=JSON
    //协议头+主机地址+接口名称+?+参数1&参数2&参数3
    //协议头(http://)+主机地址(120.25.226.186:32812)+接口名称(login)+?+参数1(username=520it)&参数2(pwd=520)&参数3(type=JSON)
    //GET请求,直接把请求参数跟在URL的后面以?隔开,多个参数之间以&符号拼接
    
    //1.确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
    
    //2.创建请求对象
    //请求对象内部默认已经包含了请求头和请求方法(GET)
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //3.获得会话对象
    NSURLSession *session = [NSURLSession sharedSession];
      
    //4.根据会话对象创建一个Task(发送请求)
    /*
     第一个参数:请求对象
     第二个参数:completionHandler回调(请求完成【成功|失败】的回调)
               data:响应体信息(期望的数据)
               response:响应头信息,主要是对服务器端的描述
               error:错误信息,如果请求失败,则error有值
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (error == nil) {
            //6.解析服务器返回的数据
            //说明:(此处返回的数据是JSON格式的,因此使用NSJSONSerialization进行反序列化处理)
            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
            
            NSLog(@"%@",dict);
        }
    }];
    
    //5.执行任务
    [dataTask resume];
}

数据业务统一为POST是推荐做法。引入GET,反而要区分两种方式,更麻烦。另外,POST的安全性要比GET高一点。

回调方式采用delegate还是block?NSURLSession采用系统的单例还是自定义的?

  • 数据业务,大多数的场景是开始网络操作,然后转菊花,数据来了之后,更新页面。基本上是一个异步转同步的使用方式。 当然,如果不愿意等,可以直接页面返回,取消这个网络操作。

  • delegate的方式可以提供更精确的控制,比如连接开始,连接成功,成功返回,等等,提供的系统函数还是比较多的。

  • block的方式就比较直接了,开始请求,然后异步返回结果。如果成功,给相应数据;如果失败,给错误信息。

  • 系统默认的超时时间是60s,如果要更改,那么就需要自定义NSURLSession

  • 系统的单例NSURLSession,是默认模式;如果要配置为及时模式和后台模式,需要进行自定义。

结合需求场景,数据业务,采用系统默认的单例NSURLSession就可以了。采用NSURLSessionDataTaskblock回调方式。采用delegate方式过于复杂,没有必要

// 1.创建一个网络路径
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://172.16.2.254/php/phonelogin?yourname=%@&yourpas=%@&btn=login",yourname,yourpass]];
// 2.创建一个网络请求
NSURLRequest *request =[NSURLRequest requestWithURL:url];
// 3.获得会话对象
NSURLSession *session = [NSURLSession sharedSession];
// 4.根据会话对象,创建一个Task任务:
NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"从服务器获取到数据");
         /*
           对从服务器获取到的数据data进行相应的处理:
         */        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingMutableLeaves) error:nil];
 }];
// 5.最后一步,执行任务(resume也是继续执行):
[sessionDataTask resume];

下载业务

  • 一般情况,下载业务涉及得很少,可以不提供

  • 要用到下载,一般会认为时间比较长,文件比较大

  • 下载一般是异步的,并且不需要转菊花,只要显示一个进度条就可以了

  • 断点续传也是一个比较多的需求

  • 切换到后台,是否可以继续下载,看具体需求场景。最好不要这样做。因为这块目前功能还比较弱,问题比较多,使用也比较麻烦

下载业务采用自定的NSURLSession,不用系统的单例。采用delegate方式,不用block方式。模式仍然采用默认的,不考虑及时模式和背景模式。使用NSURLSessionDownloadTask

图片上传和下载

  • 大图的上传和下载一般比较少,可以不做重点考虑

  • 一般图片大小限制在K级别,上M的就应该考虑切分和压缩。等待时间应当限制在10s以内。

  • 图片没下载下来之前,一般会提供一张默认图片,下载完成后替换

  • 有些场景,图片下载过程可以提供一个转菊花,下载完成后显示

  • 是否采用表单数据那个API,可以根据情况选择。普通的数据业务,外面会包一层JSON。当然,图片数据,可以看做是一种NSData的数据成员,也是完全可以当做一种普通的数据业务的。

  • 目前见到的实现方式,采用表单数据的居多。不过个人偏向统一为普通的数据业务。同时也不赞成一次传好几张图片的方式,一张张传,多调用几次接口不就好了。这样可以统一接口。

  • 当然,一般图片资源服务器和后台数据服务器的URL地址是不一样的。不过这不构成图片上传下载使用特殊接口的理由。

图片的上传下载,看做是普通数据业务,也采用NSURLSessionDataTask。使用block的方式,没有必要采用delegate。不需要考虑NSURLSessionUploadTaskNSURLSessionDownloadTask

上传业务

这个遇到的比较少,可以暂时不考虑。当然,想百度网盘那种应用,这个是重点了。一般情况,不需要考虑NSURLSessionUploadTask这种场景。

小结

  • 通过POST方式,用好NSURLSessionDataTask,解决普通数据业务就可以了。

  • 只是图片的上传下载,看做是普通的NSURLSessionDataTask就可以了。

  • NSURLSessionUploadTaskNSURLSessionDownloadTask基本不用考虑。

  • 一般用系统提供的单例NSURLSession就可以了,没有必要自定义。用block的回调方式就可以了,这个方便,没有必要用delegate

  • AFNetworkingSDWebImage这两个第三方库当然支持,省心。

  • NSURLSession本来就是多线程,异步的,再工作者线程中完成耗时工作,不需要再考虑NSOperationGCD等多线程技术。采用最简洁的使用方式才是可取的。

  • 至于任务管理,直接使用NSURLSessionDataTask就可以了,本身就有id属性,不需要额外管理了。

你可能感兴趣的:(iOS网络相关)