iOS多线程拾贝------操作巨人编程
iOS多线程拾贝------操作巨人编程
多线程
基本
实现方案:pthread - NSThread - GCD - NSOperation
Pthread
- 多平台,可移植
- c语言,要程序员管理生命周期
- 创建
//这里已经开启了多线程,直接在这里调用子线程想要调用的代码 void * run(void *pramga) { NSLog(@"-------"); return NULL; }- (IBAction)btnClick:(id)sender { pthread_t pthread; pthread_create(&pthread, NULL, run, NULL); }
NSThread
- 面向对象,简单实用
- 创建
//隐式创建并启动线程 [NSThread detachNewThreadSelector:@selector(threadRun:) toTarget:self withObject:@"etund"]; 或者 //创建线程并且启动线程 [self performSelectorInBackground:@selector(threadRun:) withObject:@"etund"]; 或者 //上述两个优点是可以快速的创建并启动线程,方便快捷,但是不能对线程进行多余属性的设置,而下面一种方法就可以对线程实例属性的设置,但是要记得要手动开启线程。 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun:) object:@"etund"]; [thread start];
GCD
- 听说全称是叫“牛逼的中枢调度器”,但是我还是喜欢叫大中央调度
- 纯C语言,有很多强大的函数
- 优势:(纯属板书)
- GCD是苹果公司为多核的并行运算提出的解决方案
- GCD会自动利用更多的CPU内核(比如双核、四核)
- GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
- 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
- 核心:清楚什么是任务,队列
- 串行与并行不能决定是否要开启新县城
- 并行表明具有创建新线程的能力,但不一定创建新线程
常用GCD内容
串行同步(并行同步/全局队列同步),由于串行同步,并行同步,以及全局队列同步都是不创建线程按顺序执行,所以归为一类来讲。(不开任何子线程,在主线程中执行)
//串行 dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_SERIAL); //并行 //dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_CONCURRENT); dispatch_sync(queue, ^{NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_sync(queue, ^{NSLog(@"%@----2",[NSThread currentThread]); }); dispatch_sync(queue, ^{NSLog(@"%@----3",[NSThread currentThread]); }); 运行结果 2015-07-08 19:09:39.611 Pthread-多平台[63090:302902] <NSThread: 0x7fc79142c1d0>{number = 1, name = main}---1 2015-07-08 19:09:39.612 Pthread-多平台[63090:302902] <NSThread: 0x7fc79142c1d0>{number = 1, name = main}----2 2015-07-08 19:09:39.612 Pthread-多平台[63090:302902] <NSThread: 0x7fc79142c1d0>{number = 1, name = main}----3
串行异步 (开启一个子线程,在子线程中执行)
dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_async(queue, ^{NSLog(@"%@---2",[NSThread currentThread]); }); dispatch_async(queue, ^{NSLog(@"%@---3",[NSThread currentThread]); });/*运行结果 2015-07-08 19:25:37.811 Pthread-多平台[68041:316565] <NSThread: 0x7fb35850fe30>{number = 3, name = (null)}---1 2015-07-08 19:25:37.811 Pthread-多平台[68041:316565] <NSThread: 0x7fb35850fe30>{number = 3, name = (null)}---2 2015-07-08 19:25:37.811 Pthread-多平台[68041:316565] <NSThread: 0x7fb35850fe30>{number = 3, name = (null)}---3 */
并行异步(全局队列异步)虽然线程的执行顺序不一样,但是任务从队列里面拿出来放进线程的顺序是按照先进先出的这是根本,基础。(有几个任务,开启几个子线程,在各自的子线程中执行)
dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_async(queue, ^{NSLog(@"%@---2",[NSThread currentThread]); }); dispatch_async(queue, ^{NSLog(@"%@---3",[NSThread currentThread]); }); // 虽然线程的执行顺序不一样,但是任务从队列里面拿出来放进线程的顺序是按照先进先出 /* *2015-07-08 19:27:46.060 Pthread-多平台[68694:318231] <NSThread: 0x7f9a89c126b0>{number = 4, name = (null)}---2 2015-07-08 19:27:46.060 Pthread-多平台[68694:318230] <NSThread: 0x7f9a8c211400>{number = 5, name = (null)}---3 2015-07-08 19:27:46.060 Pthread-多平台[68694:318171] <NSThread: 0x7f9a89f9efe0>{number = 3, name = (null)}---1 */
主队列异步,不开任何子线程,在主线程中运行,也对应了那句话,异步队列只是具有开启子线程的能力,但是不一定开子线程。
// 主队列异步(不开线程) dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"%@---2",[NSThread currentThread]); }); dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"%@---3",[NSThread currentThread]); ; }); /* 2015-07-08 19:34:25.440 Pthread-多平台[70710:322816] <NSThread: 0x7fe0d1418200>{number = 1, name = main}---1 2015-07-08 19:34:25.440 Pthread-多平台[70710:322816] <NSThread: 0x7fe0d1418200>{number = 1, name = main}---2 2015-07-08 19:34:25.440 Pthread-多平台[70710:322816] <NSThread: 0x7fe0d1418200>{number = 1, name = main}---3 */
主队列同步
- (void)gcdTest_2_4{NSLog(@"=-=-=-");// 主队列同步(阻塞)dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"%@---1",[NSThread currentThread]);});dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"%@---2",[NSThread currentThread]);});dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"%@---3",[NSThread currentThread]);});NSLog(@"=-=-=-"); }
------------至此,基本GCD队列已经被差不多就这样了,下面来一下有趣的用法
- GCD队列组,有这么一个需求,你的一个步骤要在其他步骤完成之后才能完成,也就是后续步骤要依赖于前期步骤,这是GCD队列组以及Barrier队列(栅栏队列)不失为一个好办法,
//GCD队列组方式// (线程组)(线程通讯) // dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_group_t group = dispatch_group_create();// 加载图片1dispatch_group_async(group, queue, ^{NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c2e882eb8b0df41bd5ac6e39e8.jpg"];NSData *data = [NSData dataWithContentsOfURL:url];self.image1 = [UIImage imageWithData:data];});// 加载图片2dispatch_group_async(group, queue, ^{NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/ac6eddc451da81cbd668501c5666d01608243151.jpg"];NSData *data = [NSData dataWithContentsOfURL:url];self.image2 = [UIImage imageWithData:data];});// 合并dispatch_group_notify(group, queue, ^{UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0);[self.image1 drawAsPatternInRect:CGRectMake(0, 0, 50, 100)];[self.image2 drawAsPatternInRect:CGRectMake(50, 0, 50, 100)];UIImage *image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();//GCD线程之间的通信dispatch_async(dispatch_get_main_queue(), ^{self.myView.image = image;});});//栅栏dispatch_barrier方式dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_CONCURRENT);//创建多个线程dispatch_async(queue, ^{NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c2e882eb8b0df41bd5ac6e39e8.jpg"];NSData *data = [NSData dataWithContentsOfURL:url];self.image1 = [UIImage imageWithData:data];});dispatch_async(queue, ^{NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/ac6eddc451da81cbd668501c5666d01608243151.jpg"];NSData *data = [NSData dataWithContentsOfURL:url];self.image2 = [UIImage imageWithData:data];});dispatch_barrier_async(queue, ^{});dispatch_async(queue, ^{UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0);[self.image1 drawAsPatternInRect:CGRectMake(0, 0, 50, 100)];[self.image2 drawAsPatternInRect:CGRectMake(50, 0, 50, 100)];UIImage *image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();dispatch_async(dispatch_get_main_queue(), ^{self.myView.image = image;});});
延迟加载
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{// 2秒后异步执行这里的代码... });
快速迭代,当我们不需要注重迭代的顺序,只需要快速获得子元素的时候,GCD的快速迭代为你提供了途径
// (快速迭代)dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_apply(self.view.subviews.count, queue, ^(size_t index) {id obj = self.view.subviews[index];NSLog(@"---%zu---%@",index,obj);});/*2015-07-08 22:26:39.851 Pthread-多平台[972:17366] ---0---<_UILayoutGuide: 0x7fd86b644e00; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7fd86b643ab0>>2015-07-08 22:26:39.851 Pthread-多平台[972:17444] ---2---<UIImageView: 0x7fd86b645ba0; frame = (100 100; 100 100); clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x7fd86b643290>>2015-07-08 22:26:39.851 Pthread-多平台[972:17435] ---1---<_UILayoutGuide: 0x7fd86b6457b0; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x7fd86b644040>>*/
- once一次性代码(单例模式设计),有时候我们需要用到单例模式做一些操作例如:传值时,就会用到单例设计模式,设计单例模式的方法很多,其中最重要的是要做到线程安全,而GCD就提供了这么一个结构体来保证在创建单例过程中的线程安全
ETPerson.h + (instancetype)sharePerson; ETPerson.m @implementation ETPerson static ETPerson *_person;+ (instancetype)sharePerson{static dispatch_once_t onceDispatch;dispatch_once(&onceDispatch, ^{_person = [[ETPerson alloc] init];});return _person; }+ (instancetype)allocWithZone:(struct _NSZone *)zone{static dispatch_once_t onceDispatch;dispatch_once(&onceDispatch, ^{_person = [super allocWithZone:zone];});return _person; }- (id)copyWithZone:(NSZone *)zone{return _person; } @end 调用 // onece(单例)NSLog(@"%@----%@------%@-------%@------%@-----%@",[[ETPerson alloc] init],[[ETPerson alloc] init],[ETPerson copy],[ETPerson copy],[ETPerson sharePerson],[ETPerson sharePerson]);/*运行结果2015-07-08 23:26:57.292 Pthread-多平台[1350:37528] <ETPerson: 0x7fc4bb4041c0>----<ETPerson: 0x7fc4bb4041c0>------ETPerson-------ETPerson------<ETPerson: 0x7fc4bb4041c0>-----<ETPerson: 0x7fc4bb4041c0>*/
-----------------------------------------分割线-----------07-09更-----------------------------------
NSOperation
- NSOperation是对GCD的封装,既然封装了,那么就没有GCD那么好玩,但是同时也更加便捷的实现以下常用的功能。
创建:NSOperation是一个抽象类,不能实例化,但可以通过他的子类来使用,子类分别是NSBlockOperation和NSInvocationOperation,创建方式如下。
//NSBlockOperationNSBlockOperation *opeaBlock = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"----1---%@-",[NSThread currentThread]) ;}];[opeaBlock start];或者 // NSInvocationOperationNSInvocationOperation *invoOpera = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:@"etund"];[invoOpera start];/*运行结果2015-07-09 14:00:18.610 Pthread-多平台[91622:193993] ----1---<NSThread: 0x7fc26ae193c0>{number = 1, name = main}---- etund*/
此外,还可以通过自定义类继承NSOperation来使用NSOperation,注意在继承NSOperation的实现中把你想要执行的代码块放进- (void)main;里面就行。
ETOperation.m - (void)main{NSLog(@"-----1-%@",[NSThread currentThread]); } //调用 // 自定义NSOperationETOpearation *operation = [[ETOpearation alloc] init];[operation start];/*运行结果2015-07-09 14:00:18.610 Pthread-多平台[91622:193993] ----1---<NSThread: 0x7fc26ae193c0>{number = 1, name = main}---- etund*/
- 以上线程都没有开启子线程,我们可以用NSOperationQueue与NSOperation结合使用来实现多线程操作,具体做法是把NSOperation实例加到NSOperationQueue队列中,当我们把实例加入队列中的时候,就不用主动调用start方法来开启线程了,线程会自动开启。
// NSOperationQueueNSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 自定义NSOperation实例ETOpearation *operation = [[ETOpearation alloc] init];NSBlockOperation *opeaBlock = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"----1---%@-",[NSThread currentThread]) ;}];NSInvocationOperation *invoOpera = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run:) object:@"etund"];[queue addOperation:opeaBlock];[queue addOperation:invoOpera];[queue addOperation:operation];/*运行结果2015-07-09 14:24:26.191 Pthread-多平台[98921:212686] -----1-<NSThread: 0x7ff1eab20440>{number = 5, name = (null)}2015-07-09 14:24:26.191 Pthread-多平台[98921:212687] ----1---<NSThread: 0x7ff1eab20190>{number = 4, name = (null)}-2015-07-09 14:24:26.191 Pthread-多平台[98921:212689] ----1---<NSThread: 0x7ff1eaa37910>{number = 3, name = (null)}---- etund*/
--------注意看上面运行结果,已经创建了多个线程了,至此我们成功的利用NSOperationQueue以及NSOperation实现多线程操作。
- 我们也可以直接在队列里面添加线程代码块,就可以省去新建NSOperation实例
// NSOperationQueueNSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperationWithBlock:^{NSLog(@"=======1==%@",[NSThread currentThread]);}];[queue addOperationWithBlock:^{NSLog(@"=======2==%@",[NSThread currentThread]);}];[queue addOperationWithBlock:^{NSLog(@"=======3==%@",[NSThread currentThread]);}];[queue addOperationWithBlock:^{NSLog(@"=======4==%@",[NSThread currentThread]);}];[queue addOperationWithBlock:^{NSLog(@"=======5==%@",[NSThread currentThread]);}];/*运行结果2015-07-09 14:20:30.289 Pthread-多平台[97728:209415] =======3==<NSThread: 0x7ffdf2b90220>{number = 7, name = (null)}2015-07-09 14:20:30.289 Pthread-多平台[97728:209432] =======1==<NSThread: 0x7ffdf2b8fdc0>{number = 4, name = (null)}2015-07-09 14:20:30.289 Pthread-多平台[97728:209416] =======5==<NSThread: 0x7ffdf0e015a0>{number = 5, name = (null)}2015-07-09 14:20:30.289 Pthread-多平台[97728:209414] =======2==<NSThread: 0x7ffdf0c313e0>{number = 3, name = (null)}2015-07-09 14:20:30.289 Pthread-多平台[97728:209417] =======4==<NSThread: 0x7ffdf0c314c0>{number = 6, name = (null)}*/
- 注意:我们可以通过maxConcurrentOperationCount来设置改队列可以开启的最大线程数,最小是1,当设置为0的时候,不执行队列中的任务,当为1的时候为GCD中的串行同步(并行同步,主队列异步,全局队列同步)一样效果。
-------------至此NSOperation的基本用法差不多涉及了,下面在来看看NSOperation封装带来的好处
队列挂起,suspended这个属性可以控制当前线程队列的暂停和开启,在这里,已经默认你是对iOS多线程的任务有一定了解的,suspended为NO时,回执行完当前的NSOperation实例的任务,后面的任务不会在执行知道你开启
队列挂起或开启如下。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ // NSOperationQueue // 挂起NSOperationQueue *queue = [[NSOperationQueue alloc] init];self.queue = queue;[queue addOperationWithBlock:^{for (int i = 0; i < 5000; i ++) {NSLog(@"0--%d-----%@---",i,[NSThread currentThread]);}}];[queue addOperationWithBlock:^{for (int i = 0; i < 5000; i ++) {NSLog(@"1--%d-----%@---",i,[NSThread currentThread]);}}];[queue addOperationWithBlock:^{for (int i = 0; i < 5000; i ++) {NSLog(@"2--%d-----%@---",i,[NSThread currentThread]);}}];//当执行一个任务的时候收到suspended为NO,就会执行完当前循环,停在当前任务。 } //完成一个点击事件就会改变suspended的状态 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{self.queue.suspended = !self.queue.isSuspended; }
- 队列取消,把当前队列后面的NSOperation实例全部清除掉,相对于挂起,取消是不可逆的。
- 所以在系统自定义的NSOperation实例中,取消跟挂起取YES结果一样
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{NSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperationWithBlock:^{for (int i = 0 ; i < 5000;i++){NSLog(@"----1---%@---%d-",[NSThread currentThread],i);}}];[queue addOperationWithBlock:^{for (int i = 0 ; i < 5000;i++){NSLog(@"----2---%@--%d--",[NSThread currentThread],i);}}];[queue addOperationWithBlock:^{for (int i = 0 ; i < 5000;i++){NSLog(@"----3---%@--%d--",[NSThread currentThread],i);}}];self.queue = queue; }- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{[self.queue cancelAllOperations]; } - 在自定义的NSOperation类中,当然可以把他看做一个普通的NSOperation实例对象,但是系统给NSOperation提供一个cancel属性,所以他的可控粒度更小,控制起来比较个性,要做到这一点,要在我们自定义类里面重写的main方法里面做功夫 ETOperation.m //这样就可以做到在任务里想停就马上停。 for (int i = 0; i < 5000; i++) {if (self.isCancelled) return;NSLog(@"%d---1-------%@",i,[NSThread currentThread]);} 调用 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{NSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperation:[[ETOpearation alloc] init]];self.queue = queue; }- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{[self.queue cancelAllOperations]; }
- 操作依赖,NSOperation的作用在一定程度上类似于GCD的栅栏队列(Barrier)和队列组,也就是后续步骤要在前面步骤的基础上才能执行。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{NSOperationQueue *queue = [[NSOperationQueue alloc] init];__block int i;__block int j;NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{i = 10;j = 10;}];NSBlockOperation *blockOperation_0 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"%d",j+i);}];[blockOperation_0 addDependency:blockOperation];[queue addOperation:blockOperation];[queue addOperation:blockOperation_0];}
- 上述代码没有什么实际意义,拿上面的一个需求吧,例如,下载图片,合成图片。
NSOperationQueue *queue = [[NSOperationQueue alloc] init];__block UIImage * image1;__block UIImage * image2;NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c2e882eb8b0df41bd5ac6e39e8.jpg"]]];image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/ac6eddc451da81cbd668501c5666d01608243151.jpg"]]];}];NSBlockOperation *blockOperation_0 = [NSBlockOperation blockOperationWithBlock:^{UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0);[image1 drawAsPatternInRect:CGRectMake(0, 0, 100, 200)];[image2 drawAsPatternInRect:CGRectMake(100, 0, 100, 200)];UIImage *image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();[[NSOperationQueue mainQueue] addOperationWithBlock:^{self.myView.image = image;}];}];[blockOperation_0 addDependency:blockOperation];[queue addOperation:blockOperation];[queue addOperation:blockOperation_0];
- 操作监听,在NSOperation属性中,有一个属性@property (copy) void (^completionBlock)(void)可以在某个操作执行完成时,在执行一段代码,有很多需求也用到这个属性,例如图片的下载,如上,可以试着把上面的那段代码改写,这里就随便写一段简单的代码来展示操作监听的强大。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{NSOperationQueue *queue = [[NSOperationQueue alloc] init];__block int i;__block int j;NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{i = 10;j = 10;}];blockOperation.completionBlock = ^{NSLog(@"%d",j+i);};[queue addOperation:blockOperation]; }
线程通信
- 线程之间的通信,线程的通信,在一个进程中,线程往往不是鼓励存在的,多个线程之间需要经常进行通信
- 线程间通信的体现
- 在一个线程传递数据给另外一个线程
- 在一个线程中执行完成任务后,转到另一个线程继续执行任务
NSThread的线程通信
//这个方法是指在当前线程运行完后调到主线程里面运行- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; //这个方法是指在当前线程运行完后调用另外一个线程里面运行- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait
- GCD的线程通信,GCD的线程通信十分简单,只是在代码块里面调用代码块,直接上代码吧。
从子线程回到主线程 dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 执行耗时的异步操作...dispatch_async(dispatch_get_main_queue(), ^{// 回到主线程,执行UI刷新操作 }); });
至此,iOS里面简单的多线程GCD以及NSThread以及PThread部分就入门了,明天更新NSOPeration。-----------------------------------------分割线-----------07-09更-----------------------------------
- NSOperation的线程通信
//回到主线程 [[NSOperationQueue mainQueue] addOperationWithBlock:^{}];//去子线程 NSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperationWithBlock:^{}];
转载于:https://www.cnblogs.com/superYou/p/4631761.html
iOS多线程拾贝------操作巨人编程相关推荐
- iOS多线程同时操作同一内存造成野指针
iOS多线程同时操作同一内存造成野指针 iOS多线程同时操作同一内存造成野指针,原因:崩溃线程崩中使用指针的真正创建与销毁地方在另另外一个线程中,崩溃线程只是使用这个指针拷贝. 这两个操作发送在两个线 ...
- 「面向打野编程」iOS多线程:CGD
「面向打野编程」iOS多线程:CGD 前言 参考网络其他文章而写,渣水平,抛砖引玉. 虽然Concurrent意思为并发,但由于队列的实际效果,以下称为并行队列. 当前iPhone的CPU核心数远小于 ...
- iOS多线程开发之GCD(基础篇)
总纲: GCD基本概念 GCD如何实现 GCD如何使用 队列和任务组合 一.GCD基本概念 GCD 全称Grand Central Dispatch(大中枢队列调度),是一套低层API,提供了⼀种新的 ...
- iOS多线程:『NSOperation、NSOperationQueue』详尽总结
2019独角兽企业重金招聘Python工程师标准>>> iOS多线程:『NSOperation.NSOperationQueue』详尽总结 转载: 原地址https://www.ji ...
- ios多线程开发的常用三种方式
ios多线程开发的常用三种方式 1.NSThread 2.NSOperationQueue 3.GCD NSThread: 创建方式主要有两种: [NSThread detachNewThreadSe ...
- iOS 多线程:『GCD』详尽总结
原文链接:www.jianshu.com/p/2d57c7201- 感谢大家对这篇文章的喜欢和支持.为了不辜负大家的喜欢,也为了更好的让大家了解 iOS 多线程,以及 GCD 的相关知识,我对这篇文章 ...
- IOS 多线程04-GCD详解 底层并发 API
IOS 多线程04-GCD详解 底层并发 API 注:本人是翻译过来,并且加上本人的一点见解. 前言 想要揭示出表面之下深层次的一些可利用的方面.这些底层的 API 提供了大量的灵活性,随之而来的是大 ...
- iOS多线程编程之NSThread的使用(★★★推荐,为原作者点赞★★★)
文章来源:http://blog.csdn.net/totogo2010/article/details/8010231 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThre ...
- iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(上)
2017-07-08 remember17 Cocoa开发者社区 目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 ...
最新文章
- LeetCode简单题之有序数组的平方
- php实现支付宝支付接口,PHP实现个人支付宝支付开发(二)
- Java关键字final、static、this、super使用总结
- 关于 ES6 的 let ,var和 const
- get请求乱码问题,用encodeURI和decodeURI
- Visual Studio 2017开发linux程序使用实例及原理简析
- imx6 板卡移植官方yocto版本(1_安装环境)
- 公需科目必须学吗_化学难吗?
- leetcode - 1024. 视频拼接
- .net framework处理xml
- 【英语学习】【WOTD】cerebral 释义/词源/示例
- 折叠list ExpandableList+ BaseExpandableListAdapter 自定义 折叠列表
- java 串口 rxtx_【Java】基于RXTX的Java串口通信
- java版spring cloud+spring boot+redis社交电子商务平台-spring-cloud-config
- Eclipse3.2安装简介
- python中对象的定义_全面了解python中的类,对象,方法,属性
- java+widthstep_关于IplImage中widthstep的大小与width,nchannels等的关系的问题
- 前端小白的挖坑填坑之路。
- python加不加分号区别_python加分号吗
- Excel 数据透视表教程大全之 03 刷新数据、添加多个字段作为值字段、值显示为总数的百分