iOS 解决网络请求和界面刷新顺序问题(GCD信号量实现)

来源:互联网 发布:几个c语言小游戏源码 编辑:程序博客网 时间:2024/06/13 07:08

iOS 解决网络请求和界面刷新问题(GCD信号量实现)

功能要求瞬息万变,UI界面越来越多样化…(慢慢就习惯了,手动微笑ㄒoㄒ) …开发中经常遇到,网络请求和界面刷新的问题解决方案。。。

考虑到大多数项目中都集成AFN, 本工程使用第三方库 AFN 作为网络请求方式。主要考虑功能,具体问题具体分析 ~

RequestTest 工程使用的是 Storyboard 快速开发、搭建的项目,目的是注重实现功能,主要是使用 GCD 的信号量 dispatch_semaphore_signal 效果在控制台中打印呈现 ㄒoㄒ

1. “一个任务需要等待另外一个任务执行完成后才可以执行” 问题解决

描述:
(1)网络请求。返回一个状态。(这是一个异步处理耗时操作,优化用户体验)
(2)人机交互。用户点击一个按钮,比如登录按钮,如果有登录状态,就执行任务3,如果没有,就等待任务1网络请求数据后,再继续执行任务3。
(3)通过点击按钮,想要执行的任务。

功能分解后主要实现

任务(1) :网络请求,请求成功后,数据调整。

任务(2) :按钮点击事件

#pragma mark - - (IBAction)clickLogonButton:(id)sender {    NSLog(@"执行任务2 ...");    __weak __typeof__(self) weakSelf = self;    self.block = ^() {        [weakSelf doSomething];    };    if (_states && [_states isEqualToString:@"Logon"]) {        NSLog(@"状态正常");        self.block();    } else {        NSLog(@"状态异常");        // 若计数为0则一直等待        dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);        NSLog(@"等待状态修复 ... 再次请求");        [self request];    }}

任务(3) :模拟一个执行的任务

- (void)doSomething {    NSLog(@"执行任务3: states = %@", self.states);}

2. 一个页面有多个网络请求,等待所有请求完成后,刷新页面。

主要代码:

    dispatch_group_t group = dispatch_group_create();    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        [self request1];    }) ;    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        [self request2];    }) ;    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        [self request3];    }) ;    dispatch_group_notify(group, dispatch_get_main_queue(), ^{        NSLog(@"刷新界面");    });

其中网络请求request 伪代码如下:

 dispatch_semaphore_t sema = dispatch_semaphore_create(0); [网络请求:{ 成功:dispatch_semaphore_signal(sema); 失败:dispatch_semaphore_signal(sema); }]; dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); // 通过使用GCD中的信号量可以解决多个操作共用同一资源时, 造成主线程阻塞的问题.

3. 按照顺序执行网络请求操作,使用NSOperationQueue 依赖实现

例如:

(1)下载图片(2)给图片添加水印(3)保存图片(4)主线程刷新UI界面

主要代码:

- (void)operationBlockTest {    // 处理图片的耗时操作在子线程中执行    NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blockOp 下载图片 thread = %@",[NSThread currentThread]);        [self request:@"下载图片"];    }];    NSBlockOperation *blockOp1 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blockOp1 给图片添加水印 thread = %@",[NSThread currentThread]);        [self request:@"给图片添加水印"];    }];    NSBlockOperation *blockOp2 = [NSBlockOperation blockOperationWithBlock:^{        [NSThread sleepForTimeInterval:2.0];        NSLog(@"blockOp2 保存图片 thread = %@",[NSThread currentThread]);        [self request:@" 保存图片"];    }];    // 给blockOp1添加依赖关系,使blockOp1在blcokOp执行结束后执行    [blockOp1 addDependency:blockOp];//也就是下载结束之后再给图片添加水印,然后保存图片。一种依赖关系    [blockOp2 addDependency:blockOp1];    // 创建队列(把上面要干的事情丢到队列中同时执行--有点类似GCD中的异步,并发,开启了多个线程)    NSOperationQueue *queue = [[NSOperationQueue alloc]init];    // 添加到队列    [queue addOperation:blockOp];    [queue addOperation:blockOp1];    [queue addOperation:blockOp2];    // 设置队列中操作同时执行的最大数目,也就是说当前队列中呢最多由几个线程在同时执行,一般情况下允许最大的并发数2或者3    [queue setMaxConcurrentOperationCount:3];    // 队列中可以添加其他的 BlockOperation    for (int i = 0; i<50; i++) {        NSBlockOperation *blockOpp = [NSBlockOperation blockOperationWithBlock:^{            NSLog(@"blockOpp i = %d thread = %@",i,[NSThread currentThread]);        }];        [queue addOperation:blockOpp];    }    // 刷新UI的操作依赖关系必须在主线程中执行    NSBlockOperation *blocOpMain = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blockOpMain 刷新UI 显示图片,thread = %@",[NSThread currentThread]);    }];    // 这两个操作的依赖关系,跨队列    [blocOpMain addDependency:blockOp2];    // 主队列    [[NSOperationQueue mainQueue] addOperation:blocOpMain];} 

4. 信号量实现的生产者消费者模式

GCD实现的生产者、消费者模式

#pragma mark - 生产者、消费者模式/* 信号量实现生产者、消费者模式  GCD-信号量-实现方式 */- (void)producersAndConsumersMode{    __block int product = 0;    dispatch_semaphore_t sem = dispatch_semaphore_create(0);    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //消费者队列        while (1) {            if(!dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, DISPATCH_TIME_FOREVER))){                ////非 0的时候,就是成功的timeout了,这里判断就是没有timeout   成功的时候是 0                NSLog(@"消费%d产品",product);                product--;            };        }    });    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //生产者队列        while (1) {            sleep(1); //wait for a while            product++;            NSLog(@"生产%d产品",product);            dispatch_semaphore_signal(sem);        }    });} 

最后:
Demo地址:Demo地址(点我~)

站在巨人的肩膀上造轮子,如有冒犯,请随时联系 ~


阅读全文
0 0
原创粉丝点击