iOS多线程

这些年我们用过的线程

2017-10-30  本文已影响26人  芝麻绿豆

进程

在系统中正在运行的一个应用程序。每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内。一个进程至少要有一个线程,线程是进程的基本执行单元,进程的任务都是在线程中完成的。

多线程的优缺点

实现方案

Pthread

1 特点:
(1)一套通用的多线程API
(2)适用于Unix\Linux\Windows等系统
(3)跨平台\可移植
(4)使用难度大
2 使用语言:c语言
3 使用频率:几乎不用
4 线程生命周期:由程序员进行管理

NSThread

1 特点:
(1)使用更加面向对象
(2)简单易用,可直接操作线程对象
2 使用语言:C语言
3 使用频率:偶尔使用
4 线程生命周期:由程序员进行管理
5 实现方案:线程的状态:新建、就绪、运行、阻塞、死亡

//初始化   
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(timeRun:) object:@"123"];   
thread.name = @"YAN";   
// 设置优先级:(0.0~1.0)1.0最高优先级,默认为0.5   
thread.threadPriority = 1.0;   
// 开启线程    [thread start];
// 初始化:马上创建并开启新的线程   
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"yan"];
//初始化:隐式创建   
[self performSelectorInBackground:@selector(background:) withObject:@"创建"];
GCD

1 特点:
(1)旨在替代NSThread等线程技术
(2)充分利用设备的多核(自动)
(3)并发数量、执行顺序是不可控的
(4)只支持队列的FIFO原则
2 使用语言:OC语言
3 使用频率:经常使用
4 线程生命周期:自动管理
5 底层实现:
a.基于XNU内核实现
b.属于libdispatch库
c.dispatchQueue:管理block,dispatchSource:处理事件
6 实现方案
同步执行:不具备开启新线程的能力,只能在当前线程执行任务;
异步执行:具备开启新线程的能力,在新开启的线程执行任务;
并发队列:多个任务同时执行;
串行队列:一个任务完成之后执行下一个任务;

     dispatch_queue_create(const char *_Nullable label,dispatch_queue_attr_t _Nullable attr)//队列名称、队列属性(为null时为串行队列)

①串行队列:任务添加到队列中马上执行

     dispatch_queue_t serialQueue = dispatch_queue_create("yan.liu",DISPATCH_QUEUE_SERIAL);
     dispatch_queue_t mainQueue = dispatch_get_main_queue();//主队列为系统创建的特殊串行队列,刷新UI在主队列进行;

②并发队列:将所有任务添加到队列之后才执行

dispatch_queue_t concurrentQueue = dispatch_queue_create("yan.liu", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);// 系统创建的全局并发队列
DISPATCH_QUEUE_PRIORITY_HIGH 高优先级
DISPATCH_QUEUE_PRIORITY_DEFAULT 默认优先级
DISPATCH_QUEUE_PRIORITY_LOW 低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUND 后台执行

①异步串行:开启了一个子线程,按照任务的添加顺序,并且任务添加到队列中马上执行

dispatch_async(serialQueue, ^{        NSLog(@"1-%@",[NSThread currentThread]);    });   
dispatch_async(serialQueue, ^{        NSLog(@"2-%@",[NSThread currentThread]);    });

②同步串行:没有开启新的线程,在当前线程中进行,按照任务的添加顺序,并且任务添加到队列中马上执行

dispatch_sync(serialQueue, ^{        NSLog(@"1-%@",[NSThread currentThread]);    });   
dispatch_sync(serialQueue, ^{        NSLog(@"2-%@",[NSThread currentThread]);    });

③异步并行:开启新的线程,所有任务添加完之后执行

dispatch_async(concurrentQueue, ^{        NSLog(@"1-%@",[NSThread currentThread]);    });   
dispatch_async(concurrentQueue, ^{        NSLog(@"2-%@",[NSThread currentThread]);    });

④同步并行:没有开启新的线程,所有任务添加完成之后之后

dispatch_sync(concurrentQueue, ^{        NSLog(@"1-%@",[NSThread currentThread]);    });   
dispatch_sync(concurrentQueue, ^{        NSLog(@"2-%@",[NSThread currentThread]);    });

注意:主队列不能同步执行,会造成线程卡死

    NSLog(@"start");
    dispatch_async(concurrentQueue, ^{
        NSLog(@"1-%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"2-%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"3-%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"4-%@",[NSThread currentThread]);
    });
    NSLog(@"end");
运行结果
  1. 使用dispatch_barrier_async
    NSLog(@"start");
    dispatch_async(concurrentQueue, ^{
        NSLog(@"1-%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"2-%@",[NSThread currentThread]);
    });
    dispatch_barrier_async(concurrentQueue, ^{
        NSLog(@"barrier-%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"3-%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"4-%@",[NSThread currentThread]);
    });
    NSLog(@"end");
运行结果
  1. 延迟方法:dispatch_after 延迟5S
NSLog(@"start");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"end-%@",[NSThread currentThread]);
    });
运行结果
  1. 一次性函数:dispatch_once 常用于单例
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"执行一次");
    });
  1. 快速迭代方法:与for不同的是:在并行队列中同时遍历并且创建新的线程;在串行队列中和for类似,不会创建新的线程
    dispatch_apply(5, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t count) {
        NSLog(@"%zu - %@",count,[NSThread currentThread]);
    });
运行结果
  1. 组队列:
dispatch_group_wait(group, DISPATCH_TIME_FOREVER) 等待group执行完毕继续往下进行,会阻塞线程;
dispatch_group_notify 等待group执行完毕执行block,不会阻塞进程;
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, globalQueue, ^{
        dispatch_apply(5, concurrentQueue, ^(size_t count) {
            NSLog(@"%zu -1- %@",count,[NSThread currentThread]);
        });
    });
    dispatch_group_async(group, globalQueue, ^{
        dispatch_apply(5, serialQueue, ^(size_t count) {
            NSLog(@"%zu -2- %@",count,[NSThread currentThread]);
        });
    });
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"回到 - %@",[NSThread currentThread]);
    });
    NSLog(@"1234567");
运行结果
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, globalQueue, ^{
        dispatch_apply(5, concurrentQueue, ^(size_t count) {
            NSLog(@"%zu -1- %@",count,[NSThread currentThread]);
        });
    });
    dispatch_group_async(group, globalQueue, ^{
        dispatch_apply(5, serialQueue, ^(size_t count) {
            NSLog(@"%zu -2- %@",count,[NSThread currentThread]);
        });
    });
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
//    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//        NSLog(@"回到 - %@",[NSThread currentThread]);
//    });
    NSLog(@"1234567");
运行结果
注意:dispatch_group_notify不能与 dispatch_async结合使用,否则会导致group任务没有执行完毕,就执行了dispatch_group_notify
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, globalQueue, ^{
        dispatch_async(concurrentQueue, ^{
            for (int i = 0; i < 3; i ++) {
                NSLog(@"%d -1- %@",i,[NSThread currentThread]);
            }
        });
    });
    dispatch_group_async(group, globalQueue, ^{
        dispatch_async(concurrentQueue, ^{
            for (int i = 0; i < 3; i ++) {
                sleep(1);
                NSLog(@"%d -2- %@",i,[NSThread currentThread]);
            }
        });
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"回到 - %@",[NSThread currentThread]);
    });
    NSLog(@"1234567");
运行结果

dispatch_group_enter(group); …… dispatch_group_leave(group);中间的任务由group管理,dispatch_group_enter(group)group任务加1,dispatch_group_leave(group)group任务减1;

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);
    dispatch_async(concurrentQueue, ^{
        for (int i = 0; i < 3; i ++) {
            sleep(1);
            NSLog(@"%d -1- %@",i,[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_sync(concurrentQueue, ^{
        for (int i = 0; i < 3; i ++) {
            NSLog(@"%d -2- %@",i,[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
       NSLog(@"回到 - %@",[NSThread currentThread]);
    });
    NSLog(@"123456789");
运行结果
  1. 信号量:dispatch_semaphore

是一个整形值并且具有一个初始计数值,并且支持两个操作:信号通知和等待。当一个信号量被信号通知,其计数会被增加。当一个线程在一个信号量上等待时,线程会被阻塞(如果有必要的话),直至计数器大于零,然后线程会减少这个计数,并继续执行下面的语句。

①创建信号量: dispatch_semaphore_t sema = dispatch_semaphore_create(0);
②发送信号: dispatch_semaphore_signal(sema) 信号量加1
③等待信号: dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER) 信号量减1

timeout:dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC) 5秒
DISPATCH_TIME_FOREVER 遥远的未来
DISPATCH_TIME_NOW 当前时间
在等待时间timeout期间没有获得信号量或者信号量一直为0,其所处的线程将继续执行下面的语句;

  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    __block long x = 0;
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"1-%ld",x);
        sleep(2);
        x=dispatch_semaphore_signal(sema);
        NSLog(@"2-%ld",x);
    });
    NSLog(@"3-%ld",x);
    x=dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    NSLog(@"4-%ld",x);
运行结果
  1. dispatch_suspend(queue)挂起queue:不会挂起正在进行的任务,当前任务完成之后挂起之后的任务
  2. dispatch_resume(queue)恢复queue:恢复被挂起的queue
    注意:dispatch_suspend/dispatch_resume对于系统的queue不起作用;挂起 dispatch_sync中的queue会造成死锁;成对出现;
  3. dispatch_retain() 、dispatch_release() :ARC中并不需要自己管理
NSOperation

1 特点:
(1)基于GCD(底层是GCD)封装的API
(2)比GCD多了一些更简单实用的功能
(3)使用更加面向对象
(4)可以控制并发数量,调整执行顺序和操作之间的依赖关系
(5)执行速度没有GCD快
2 使用语言:OC语言
3 使用频率:经常使用
4 线程生命周期:自动管理
5 实现方案:

执行操作:start
取消操作: cancel
监听操作:设置在start之前
    [invocation setCompletionBlock:^{
        NSLog(@"执行完毕");
    }];
    invocation.completionBlock = ^{
        NSLog(@"执行完毕");
    };
    NSInvocationOperation *invocation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocation:) object:@"yan"];
    [invocation start];
    - (void)invocation:(id)obj{
         NSLog(@"%@--%@",obj,[NSThread currentThread]);
    }
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1--%@",[NSThread currentThread]);
    }];
    [blockOperation addExecutionBlock:^{
        NSLog(@"2--%@",[NSThread currentThread]);
    }];
    [blockOperation start];

主队列: NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
其他队列: NSOperationQueue *otherQueue = [[NSOperationQueue alloc] init]; 通过设置并发数确定队列是并发还是串行、异步

addOperationWithBlock:默认异步并发, maxConcurrentOperationCount默认为-1,即并发;设置为1时,otherQueue为串行队列,大于1位并行队列;

    otherQueue.maxConcurrentOperationCount = 1;
    [otherQueue addOperationWithBlock:^{
        NSLog(@"1--%@",[NSThread currentThread]);
    }];
    [otherQueue addOperationWithBlock:^{
        NSLog(@"2--%@",[NSThread currentThread]);
        [NSThread sleepForTimeInterval:1.0];
    }];
    [otherQueue addOperationWithBlock:^{
        NSLog(@"3--%@",[NSThread currentThread]);
    }];
运行结果

addOperation:
添加NSInvocationOperation:在新线程中执行;
添加NSBlockOperation:异步并发
[otherQueue cancelAllOperations];取消这句代码之前队列里添加的所有没有执行的任务;

    [otherQueue addOperationWithBlock:^{
        NSLog(@"1--%@",[NSThread currentThread]);
    }];
    [otherQueue addOperationWithBlock:^{
        NSLog(@"2--%@",[NSThread currentThread]);
        [NSThread sleepForTimeInterval:1.0];
    }];
    [otherQueue cancelAllOperations];
    [otherQueue addOperationWithBlock:^{
        NSLog(@"3--%@",[NSThread currentThread]);
    }];
运行结果

[otherQueue setSuspended:YES];YES:暂停;NO:恢复
[invocation setQueuePriority:NSOperationQueuePriorityLow];
[blockOperation4 setQueuePriority:NSOperationQueuePriorityHigh]; 设置queue中的优先级,相对于同一个queue;对执行顺序不起绝对想作用;好像并没有起作用;

添加依赖:可以不同queue之间创建依赖,但是不能创建环形依赖;
依赖影响任务的执行顺序:

// 顺序随机
    [otherQueue addOperation:blockOperation1];
    [otherQueue addOperation:blockOperation2];
    [otherQueue addOperation:blockOperation3];
    [otherQueue addOperation:blockOperation4];
    [blockOperation1 addDependency:blockOperation4];
    [blockOperation4 addDependency:blockOperation2];
添加依赖后的运行结果
等待任务完成:等待单个任务完成:waitUntilFinished 阻塞线程(当前线程与主线程),直到任务完成;要写在任务添加到queue之后,否则阻塞线程;阻塞waitUntilFinished之后的命令;
    [otherQueue addOperation:blockOperation1];
    [otherQueue addOperation:blockOperation2];
    [otherQueue addOperation:blockOperation3];
    [blockOperation1 waitUntilFinished];
    [otherQueue addOperation:blockOperation4];
    NSLog(@"end--%@",[NSThread currentThread]);
运行结果

这样添加不阻塞主线程:

    NSOperationQueue *otherQueue = [[NSOperationQueue alloc] init];
    NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1--%@",[NSThread currentThread]);
        [NSThread sleepForTimeInterval:2.0];
    }];
    NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"2--%@",[NSThread currentThread]);
    }];
    NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
        [blockOperation1 waitUntilFinished];
        NSLog(@"3--%@",[NSThread currentThread]);
    }];
    NSBlockOperation *blockOperation4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"4--%@",[NSThread currentThread]);
    }];
    [otherQueue addOperation:blockOperation1];
    [otherQueue addOperation:blockOperation2];
    [otherQueue addOperation:blockOperation3];
    [otherQueue addOperation:blockOperation4];
    NSLog(@"end--%@",[NSThread currentThread]);
运行结果
等待queue中的任务完成:阻塞线程(当前线程和主线程),直到queue添加的任务完成;在waitUntilAllOperationsAreFinished之后添加的任务不算在内;
    [otherQueue addOperation:blockOperation1];
    [otherQueue addOperation:blockOperation2];
    [otherQueue waitUntilAllOperationsAreFinished];
    [otherQueue addOperation:blockOperation3];
    [otherQueue addOperation:blockOperation4];
    NSLog(@"end--%@",[NSThread currentThread]);
运行结果

线程安全

多个线程访问同一块资源会产生线程安全问题;

如果使用锁机制,则不要使用volatile关键字;

 NSLock *lock = [[NSLock alloc] init];   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [lock lock];
        NSLog(@"加锁%@",[NSThread currentThread]);
        sleep(3);
        NSLog(@"解锁%@",[NSThread currentThread]);
        [lock unlock];
    });
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if ([lock tryLock]) {
            NSLog(@"锁可用%@",[NSThread currentThread]);
            [lock unlock];
        }else{
            NSLog(@"锁不可用%@",[NSThread currentThread]);
        }
        NSLog(@"%@",[NSThread currentThread]);
    });
运行结果

[lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:4.0]]:在时间限制内获取锁,时间限制内获取失败会阻塞线程,直到获取成功;时间超时后不会阻塞线程;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if ([lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:4.0]]) {
            NSLog(@"锁可用%@",[NSThread currentThread]);
            [lock unlock];
        }else{
            NSLog(@"锁不可用%@",[NSThread currentThread]);
        }
        NSLog(@"%@",[NSThread currentThread]);
    });
运行结果
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if ([lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:2.0]]) {
            NSLog(@"锁可用%@",[NSThread currentThread]);
            [lock unlock];
        }else{
            NSLog(@"锁不可用%@",[NSThread currentThread]);
        }
        NSLog(@"%@",[NSThread currentThread]);
    });
运行结果
    NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        static void (^lockMethod)(int);
        lockMethod = ^(int count){
            [recursiveLock lock];
            if (count < 5) {
                NSLog(@"%d",count);
                lockMethod(count+1);
            }
            [recursiveLock unlock];
            NSLog(@"%d---%@",count,[NSThread currentThread]);
        };
        lockMethod(0);
    });

[recursiveLock tryLock]/ [recursiveLock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]:同NSLock

[conditionLock lockWhenCondition:0]:condition为0 的时候加锁;
[conditionLock tryLockWhenCondition:1]:尝试获取condition为1的锁;不会阻塞线程;
[conditionLock unlockWithCondition:1]:解锁,并将condition设置为1;
[conditionLock lockWhenCondition:1 beforeDate:[NSDate dateWithTimeIntervalSinceNow:3]]:在时间限制内获取condition为1的锁;阻塞当前线程;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [conditionLock lockWhenCondition:1];
        NSLog(@"条件加锁--1--%@",[NSThread currentThread]);
        NSLog(@"condition-1-%ld",conditionLock.condition);
        sleep(2);
        [conditionLock unlock];
        NSLog(@"解锁--1--%@",[NSThread currentThread]);
    });
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [conditionLock lockWhenCondition:0];
        NSLog(@"条件加锁--0--%@",[NSThread currentThread]);
        NSLog(@"condition-0-%ld",conditionLock.condition);
        sleep(2);
        [conditionLock unlockWithCondition:1];
        NSLog(@"解锁--0--%@",[NSThread currentThread]);
    });
运行结果

[condition signal]:唤醒最先进入wait的线程
[condition broadcast]:换线所有进入wait状态的线程

    NSCondition *condition = [[NSCondition alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [condition lock];
        NSLog(@"加锁 --1--%@",[NSThread currentThread]);
        [condition wait];
        NSLog(@"wait-1-%@",[NSThread currentThread]);
        [condition unlock];
        NSLog(@"解锁 --wait1--%@",[NSThread currentThread]);
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [condition lock];
        NSLog(@"加锁 --2--%@",[NSThread currentThread]);
        [condition wait];
        NSLog(@"wait-2-%@",[NSThread currentThread]);
        [condition unlock];
        NSLog(@"解锁 --wait2--%@",[NSThread currentThread]);
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [condition lock];
        NSLog(@"加锁 ----%@",[NSThread currentThread]);
        [condition signal];
        NSLog(@"唤醒 ----%@",[NSThread currentThread]);
        [condition unlock];
        NSLog(@"解锁 ----%@",[NSThread currentThread]);
    });
运行结果
//    @property(nonatomic, assign) NSInteger count;
    static void (^myBlock)();
    myBlock = ^(){
        @synchronized(self){
            self.count += 1;// 如果不使用@synchronized,可能出现同时被修改的情况,即相同的值;
        };
    };
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        myBlock();
        NSLog(@"1--%ld--%@",self.count,[NSThread currentThread]);
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        myBlock();
        NSLog(@"2--%ld--%@",self.count,[NSThread currentThread]);
    });
运行结果

线程通信

一个线程传递数据给另一个线程;一个线程执行完特定任务之后,执行另一个线程;

[self performSelectorOnMainThread:@selector(run:) withObject:@"主线程" waitUntilDone:YES];   
[self performSelector:@selector(run:) onThread:thread withObject:@"指定线程" waitUntilDone:YES];   
[self performSelector:@selector(run:) withObject:@"当前线程"];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"其他操作");
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"进行UI刷新操作");
        });
    });
    NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
    NSOperationQueue *otherQueue = [[NSOperationQueue alloc] init];
    [otherQueue addOperationWithBlock:^{
        NSLog(@"一些操作%@",[NSThread currentThread]);
        [mainQueue addOperationWithBlock:^{
            NSLog(@"刷新UI%@",[NSThread currentThread]);
        }];
    }];
上一篇 下一篇

猜你喜欢

热点阅读