浅谈如何在项目中处理页面中的多个网络请求

在开发中很多时候会有这样的场景,同一个界面有多个请求,而且要在这几个请求都成功返回的时候再去进行下一操作,对于这种场景,如何来设计请求操作呢?今天我们就来讨论一下有哪几种方案。

分析:

在网络请求的开发中,经常会遇到两种情况,一种是多个请求结束后统一操作,在一个界面需要同时请求多种数据,比如列表数据、广告数据等,全部请求到后再一起刷新界面。另一种是多个请求顺序执行,比如必须先请求个人信息,然后根据个人信息请求相关内容。这些要求对于普通的操作是可以做到并发控制和依赖操作的,但是对于网络请求这种需要时间的请求来说,效果往往与预期的不一样。因为网络请求是异步的,并不知道什么时候网络请求。很多开发人员为了省事,对于网络请求必须满足一定顺序这种情况,一般都是嵌套网络请求,即一个网络请求成功之后再请求另一个网络请求,虽然采用嵌套请求的方式能解决此问题,但存在很多问题,如:其中一个请求失败会导致后续请求无法正常进行、多个请求在时间上没有复用,即无并发性。来看一下下面几种方案:

dispatch_semaphore 信号量

信号量是一个整数,在创建的时候会有一个初始值,这个初始值往往代表我要控制的同时操作的并发数。
在操作中,对信号量会有两种操作:信号通知与等待。信号通知时,信号量会+1,等待时,如果信号量大于0,则会将信号量-1,否则,会等待直到信号量大于0。什么时候会大于零呢?往往是在之前某个操作结束后,我们发出信号通知,让信号量+1。

在 GCD 中,提供了以下这么几个函数,可用于请求同步等处理,模拟同步请求:

// 创建一个信号量(semaphore)
dispatch_semaphore_t semaphore = dispatch_semaphore_create(value);
// 等待,直到信号量大于0时,即可操作,同时将信号量-1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 信号通知,即让信号量+1
dispatch_semaphore_signal(semaphore);

在使用的时候,往往会创建一个信号量,然后进行多个操作,每次操作都等待信号量大于0再操作,同时信号量-1,操作完后将信号量+1。当信号量就减小到0了,这时候wait操作会起作用,DISPATCH_TIME_FOREVER 表示会永远等待,一直等到信号量大于0,也就是有操作完成了,将信号量+1了,这时候才可以结束等待,进行操作,并且将信号量-1,这样新的任务又要等待。

下面我们展示一段代码来模拟同步请求:

image.png

从打印结果可以看出,在每个请求开始之前,我们创建一个信号量,初始为0,在请求操作之后,我们设一个 dispatch_semaphore_wait,在请求到结果之后,再将信号量+1,也即是 dispatch_semaphore_signal。这样做的目的是保证在请求结果没有返回之前,一直让线程等待在那里,这样一个线程的任务一直在等待,就不会算作完成,notify 的内容也就不会执行了,直到每个请求的结果都返回了,线程任务才能够结束,这时候 notify 也才能够执行。

dispatch_group(组)

可以使用 dispatch_group_async 函数将多个任务关联到一个 dispatch_group 和相应的 queue 中,dispatch_group 会并发地同时执行这些任务。而且 dispatch_group 可以用来阻塞一个线程,直到 dispatch_group 关联的所有的任务完成执行。有时候必须等待任务完成的结果,然后才能继续后面的处理。

主要使用如下两个函数:

dispatch_group_enter(group);
dispatch_group_leave(group);

注意:
以上这两个函数必须配对使用,否则 dispatch_group_notify 不会触发。

下面我们展示一段代码来模拟同步请求:

image.png

dispatch_group 会等和它关联的所有的 dispatch_queue_t 上的任务都执行完毕才会发出同步信号,dispathc_group_notify 的代码块 block 会被执行。从控制台的打印结构可以看出,如果将上面三个操作改成真实的网络操作后,这个简单的做法会变得无效,因为网络请求需要时间,而线程的执行并不会等待请求完成后才真正算作完成,而是只负责将请求发出去,线程就认为自己的任务算完成了,当三个请求都发送出去,就会执行 dispathc_group_notify 中的内容,但请求结果返回的时间是不一定的,也就导致界面都刷新了,请求才返回,这就是无效的。

image.png

notify 的作用就是在 group 中的其他操作全部完成后,再操作自己的内容,所以我们会看到上面事件 A、B、C 执行之后,才执行事件 E。
dispatch_async 相比,当我们调用 ndispatch_group_enter 后再调用 ndispatch_group_level 时,dispatch_group_notifydispatch_group_wait 会收到同步信号;这个特点使得它非常适合处理异步任务的同步当异步任务开始前调用 dispatch_group_enter 异步任务结束后调用 dispatch_group_leve

NSOperationQueue

NSOperationQueue 只有两种队列,即主队列和并行队列。通过 [[NSOperationQueue alloc] init]; 创建的队列都是并行队列,并且可以将一个或多个 NSOperation 对象放到队列中去执行,而且是异步执行的,一个 NSOperation 对象可以通过调用 start 方法来执行任务,但是默认是同步执行的。则主队列通过 [NSOperationQueue mainQueue]; 获得,而且其中所有 NSOperation 都会在主线程中执行。

当然也可以利用 NSOperationQueue 的线程依赖,当某个 NSOperation 对象依赖于其它 NSOperation 对象的完成时,就可以通过 addDependency 方法添加一个或者多个依赖的对象,只有所有依赖的对象都已经完成操作,当前 NSOperation 对象才会开始执行操作。需要先添加依赖关系,再将操作添加到队列中。另外,通过 removeDependency 方法来删除依赖对象。

结论

在开发过程中,我们应尽量避免发送同步请求;假设我们一个页面需要同时进行多个请求,他们之间倒是不要求顺序关系,但是要求等他们都请求完毕了再进行界面刷新或者其他什么操作。并且在某个操作依赖于其他几个任务的完成时,采用 dispatch_group or dispatch_semaphore 来实现同步等处理。如果在某个操作依赖于其他几个任务的完成,可以考虑使用 NSOperationQueue 的线程之间依赖。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容

  • 1.属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令伟阅读 1,053评论 0 10
  • iOS面试小贴士 ———————————————回答好下面的足够了------------------------...
    不言不爱阅读 1,978评论 0 7
  • 多线程、特别是NSOperation 和 GCD 的内部原理。运行时机制的原理和运用场景。SDWebImage的原...
    LZM轮回阅读 2,007评论 0 12
  • 史上最全的iOS面试题及答案 iOS面试小贴士———————————————回答好下面的足够了----------...
    Style_伟阅读 2,354评论 0 35
  • 基础 1.为什么说Objective-C是一门动态的语言? 所谓的动态类型语言,意思就是类型的检查是在运行时做的。...
    阳明先生_X自主阅读 1,017评论 0 17