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

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地址(点我~)

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值