把握AFNet网络请求完成的正确时机

640?wx_fmt=jpeg

黑客技术 点击右侧关注,了解黑客的世界! 640?wx_fmt=jpeg

640?wx_fmt=jpeg

Java开发进阶 点击右侧关注,掌握进阶之路! 640?wx_fmt=jpeg

640?wx_fmt=jpeg

Linux编程 点击右侧关注,免费入门到精通! 640?wx_fmt=jpeg


作者丨卖报的小画家Sure
https://www.jianshu.com/p/506ec0e95938


前言

对于iOS开发中的网络请求模块,AFNet的使用应该是最熟悉不过了,但你是否把握了网络请求正确的完成时机? 本篇文章涉及线程同步、线程依赖、线程组等专用名词的含义,若对上述名词认识模糊,可先进行查阅理解后阅读本文。 如果你也纠结于文中所述问题,可进行阅读希望对你有所帮助。 大神无视勿喷。
在真实开发中,我们通常会遇到如下问题:
一、某界面存在多个请求,希望所有请求均结束才进行某操作。

对于这一问题的解决方案很容易想到通过线程组进行实现。 代码如下:
 
  
 
打印如下
 
  
 
根据打印结果观察可能并没有什么问题,但需要注意的是Request_1、Request_2等在真实开发中通常对应为某个网络请求。 而网络请求通常为异步,那这时是否还会有同样结果呢?
口说无凭,我们将NSLog(@"Request");部分替换为真正的网络请求。
对于App请求数据大部分人都会选择AFNetworking。 使用AFN异步请求,请求的数据返回后,就刷新相关UI。 如果某一个页面有多个网络请求,我们假设有三个请求,A、B、C,而且UI里的数据必须等到A、B、C全部完成后刷新后才显示。
这里我们书写一个网络请求通用方法,假设同时请求某新闻列表的3页数据,每页均为一个独立的网络请求。 使用我们最常用的AFNet请求,方法如下(真实开发中可能为banner数据请求、主体网络请求、广告网络请求等):
 
  
 
request_B、request_C分别为请求第二页与第三页数据,这里不重复书写。 为了显示更加明显,在请求中打印了对应新闻的标题内容。
运行打印如下:
 
  
 
运行后马上接收到了线程组完成的提示,之后数据才依次请求下来,很明显三个单纯的AFNet请求已经不能满足我们的需求了。 线程组完成时并没有在我们希望的时候给予通知。 在真实开发中会造成的问题为多个请求均加载完成,但界面已在未得到数据前提前刷新导致界面空白。

因此对于这种问题需要另辟蹊径,这里我们就要借助GCD中的信号量dispatch_semaphore进行实现,即营造线程同步情况。
dispatch_semaphore信号量为基于计数器的一种多线程同步机制。 用于解决在多个线程访问共有资源时候,会因为多线程的特性而引发数据出错的问题。
如果semaphore计数大于等于1,计数-1,返回,程序继续运行。 如果计数为0,则等待。
dispatch_semaphore_signal(semaphore)为计数+1操作。 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)为设置等待时间,这里设置的等待时间是一直等待。 我们可以通俗的理解为单柜台排队点餐,计数默认为0,每当有顾客点餐,计数+1,点餐结束-1归零继续等待下一位顾客。 比较类似于NSLock。

我们将网络请求通用方法进行修改如下:
 
  
 
为方便阅读,伪代码如下:
 
  
 
这时我们再运行程序,打印如下:
 
  
 
运行打印可见,通过信号量dispatch_semaphore完美的解决了此问题,并且网络请求仍为异步,不会堵塞当前主线程。
二、某界面存在多个请求,希望请求依次执行。

对于这个问题通常会通过线程依赖进行解决,因 使用GCD设置线程依赖比较繁琐,这里通过NSOperationQueue进行实现,这里采用比较经典的例子,三个任务分别为下载图片,打水印和上传图片,三个任务需异步执行但需要顺序性。 代码如下,下载图片、打水印、上传图片仍模拟为分别请求新闻列表3页数据。
 
  
 
首先我们使用未添加信号量dispatch_semaphore时运行,打印如下
 
  
 
根据打印结果可见,若不对请求方法做处理,其运行结果并不是我们想要的,联系实际需求,A、B、C请求分别对应下载图片、打水印、上传图片,而此时运行顺序则为B->A->C,在未获得图片时即执行打水印操作明显是错误的。 重复运行亦会出现不同结果,即请求不做处理,其结果不可控无法预测。 线程依赖设置并未起到作用。
解决此问题的方法仍可通过信号量dispatch_semaphore进行解决。 我们将请求方法替换为添加dispatch_semaphore限制的形式。
 
  
 
再次重复运行,我们会发现每次运行结果均一致,A、B、C三任务异步顺序执行(A->B->C)

通过重复运行打印结果可证实确实实现了我们想要的效果。 这样即解决了所提出的问题二。
后续

在开发中我们会遇到很多需要进行线程同步或请求同步的情况。 比如弹出视图设置某功能,在点击确认按钮时发生请求,在请求成功同时销毁弹出视图等,均需要保证在请求真正完成时进行下一步操作。 因此把握网络请求完成的正确时机还是很有必要的。 暂时写到这里,若有更好实例会继续在本文更新。

 推荐↓↓↓ 

640?wx_fmt=jpeg

?16个技术公众号】都在这里!

涵盖:程序员大咖、源码共读、程序员共读、数据结构与算法、黑客技术和网络安全、大数据科技、编程前端、Java、Python、Web编程开发、Android、iOS开发、Linux、数据库研发、幽默程序员等。

640?wx_fmt=png万水千山总是情,点个 “ 在看” 行不行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值