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]);
});
运行结果
-- ::39.611 Pthread-多平台[:] <NSThread: 0x7fc79142c1d0>{number = , name = main}---
-- ::39.612 Pthread-多平台[:] <NSThread: 0x7fc79142c1d0>{number = , name = main}----
-- ::39.612 Pthread-多平台[:] <NSThread: 0x7fc79142c1d0>{number = , name = main}----串行异步 (开启一个子线程,在子线程中执行)
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, );
dispatch_group_t group = dispatch_group_create();
// 加载图片1
dispatch_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];
});
// 加载图片2
dispatch_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(, ), NO, );
[self.image1 drawAsPatternInRect:CGRectMake(, , , )];
[self.image2 drawAsPatternInRect:CGRectMake(, , , )];
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(, ), NO, );
[self.image1 drawAsPatternInRect:CGRectMake(, , , )];
[self.image2 drawAsPatternInRect:CGRectMake(, , , )];
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, );
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,创建方式如下。
//NSBlockOperation
NSBlockOperation *opeaBlock = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"----1---%@-",[NSThread currentThread]) ;
}];
[opeaBlock start];
或者
// NSInvocationOperation
NSInvocationOperation *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]);
}
//调用
// 自定义NSOperation
ETOpearation *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方法来开启线程了,线程会自动开启。
// NSOperationQueue
NSOperationQueue *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实例
// NSOperationQueue
NSOperationQueue *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 = ; i < ; i ++) {
NSLog(@"0--%d-----%@---",i,[NSThread currentThread]);
}
}]; [queue addOperationWithBlock:^{
for (int i = ; i < ; i ++) {
NSLog(@"1--%d-----%@---",i,[NSThread currentThread]);
}
}];
[queue addOperationWithBlock:^{
for (int i = ; i < ; 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 = ; i < ;i++){
NSLog(@"----1---%@---%d-",[NSThread currentThread],i);
}
}]; [queue addOperationWithBlock:^{
for (int i = ; i < ;i++){
NSLog(@"----2---%@--%d--",[NSThread currentThread],i);
}
}]; [queue addOperationWithBlock:^{
for (int i = ; i < ;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 = ; i < ; 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 = ;
j = ;
}]; 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(, ), NO, );
[image1 drawAsPatternInRect:CGRectMake(, , , )];
[image2 drawAsPatternInRect:CGRectMake(, , , )];
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 = ;
j = ;
}]; 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, ), ^{
// 执行耗时的异步操作...
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:^{ }];
iOS多线程拾贝------操作巨人编程的更多相关文章
- iOS多线程编程
废话不多说,直接上干货.先熟悉一下基本知识,然后讲一下常用的两种,NSOperation和GCD. 一.基础概念 进程: 狭义定义:进程是正在运行的程序的实例(an instance of a com ...
- 「面向打野编程」iOS多线程:CGD
「面向打野编程」iOS多线程:CGD 前言 参考网络其他文章而写,渣水平,抛砖引玉. 虽然Concurrent意思为并发,但由于队列的实际效果,以下称为并行队列. 当前iPhone的CPU核心数远小于 ...
- iOS多线程编程(四)------ GCD(Grand Central Dispatch)
一.简单介绍 是基于C语言开发的一套多线程开发机制.也是眼下苹果官方推荐的多线程开发方法.用起来也最简单.仅仅是它基于C语言开发,并不像NSOperation是面向对象的开发.而是全然面向过程的.假设 ...
- iOS多线程编程指南
iOS多线程编程指南(拓展篇)(1) 一.Cocoa 在Cocoa上面使用多线程的指南包括以下这些: (1)不可改变的对象一般是线程安全的.一旦你创建了它们,你可以把这些对象在线程间安全的传递.另一方 ...
- iOS多线程编程原理及实践
摘要:iOS开发中,开发者不仅要做好iOS的内存管理,而且如果你的iOS涉及多线程,那你也必须了解iOS编程中对多线程的限制,iOS主线程的堆栈大小为1M,其它线程均为512KB,且这个限制开发者是无 ...
- iOS多线程编程--NSOperation(转)
这篇文章写得非常不错,基础用法都涉及到了,我把文章提到的例子都写到了demo里面, 原文地址: iOS多线程--彻底学会多线程之『NSOperation』 demo下载:https://github. ...
- iOS 多线程编程
参考文章: iOS多线程编程之NSThread的使用http://blog.csdn.net/totogo2010/article/details/8010231 iOS多线程编程之NSOperati ...
- iOS多线程技术方案
iOS多线程技术方案 目录 一.多线程简介 1.多线程的由来 2.耗时操作的模拟试验 3.进程和线程 4.多线程的概念及原理 5.多线程的优缺点和一个Tip 6.主线程 7.技术方案 二.Pthrea ...
- iOS多线程到底不安全在哪里?
iOS多线程安全的概念在很多地方都会遇到,为什么不安全,不安全又该怎么去定义,其实是个值得深究的话题. 共享状态,多线程共同访问某个对象的property,在iOS编程里是很普遍的使用场景,我们就从P ...
随机推荐
- ANDROID_MARS学习笔记_S01_008Linear_layout例子
1.netstone_layout.xml <?xml version="1.0" encoding="utf-8"?> <LinearLay ...
- python-append()方法
append() 方法向列表的尾部添加一个新的元素.只接受一个参数. >>> mylist = [1,2,3,4] >>> mylist [1, 2, 3, 4] ...
- linux page cache和buffer cache
主要区别是,buffer cache缓存元信息,page cache缓存文件数据 buffer 与 cache 是作为磁盘文件缓存(磁盘高速缓存disk cache)来使用,主要目的提高文件系统系性能 ...
- LINQ语句
http://wenku.baidu.com/link?url=hPKqDWql7DNr6W2MsINakjRYYNXmXywB_U3h9FFMeFjcToYpusI2fYKgHjZSRq7r3ULG ...
- Hibernate征途(五)之继承映射和组件映射
之所以把这两种映射放到一起说,是因为二者都是以复用为目的,减少了代码和配置量,这是相同点:二者之间的不同点类似继承和实现的区别:继承的类是一个事物的抽象,而实现的接口仅仅是功能的抽象. 继承映射 如上 ...
- 再谈 retain,copy,mutableCopy(官方SDK,声明NSString都用copy非retain)
之前一直以为retain就是简单的计数器+1,copy就是重新开辟内存复制对象: 其实不是这样,原来之前的自己独自徘徊于糊涂之中. (官方SDK,对NSString属性的定义都是用copy,而不是re ...
- JSP内置标签 JSP中JavaBean标签 JSP开发模式 EL和JSTL快速入门
2 JSP内置标签(美化+业务逻辑) 1)为了取代<%%>脚本形式,使用JSP标签/JSP动作,目的:与JSP页面的美化,即JSP面页都是由标签组成,不再有其它的内容 2)JSP内 ...
- 【HDOJ】4341 Gold miner
分组01背包.在一条直线上的点归为一组. /* 4341 */ #include <iostream> #include <sstream> #include <stri ...
- Visual Studio Developer Command Prompt删除localdb的方法
PM> sqllocaldb.exe stop v11. LocalDB instance "v11.0" stopped. PM> sqllocaldb.exe de ...
- (转载)有关反演和gcd
tips : 积性函数 F (n) = Π F (piai ) 若F (n), G (n)是积性函数则 F (n) * G (n) Σd | n F (n) 是积性函数 n = Σd | n φ ( ...