iOS多线程的几种创建方式
1.NSThread
2.NSOperationQueue
3.GCD
NSThread:
创建方式主要有两种:
[NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil]; 和 NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:@selector(myThreadMainMethod:) object:nil]; [myThread start]; //启动线程
这两种方式的区别是:前一种一调用就会立即创建一个线程来做事情;而后一种虽然你 alloc 了也 init了,但是要直到我们手动调用 start 启动线程时才会真正去创建线程。这种延迟实现思想在很多跟资源相关的地方都有用到。后一种方式我们还可以在启动线程之前,对线程进行配置,比如设置 stack 大小,线程优先级。
此外还有一种间接的方式:利用NSObject的方法
performSelectorInBackground:withObject: 来创建一个线程:
[myObj performSelectorInBackground:@selector(myThreadMainMethod) withObject:nil]; //在后台运行某一个方法
其效果与 NSThread 的 detachNewThreadSelector:toTarget:withObject: 是一样的。
NSOperationQueue
The NSOperation class is an abstract class you use to encapsulate the code and data associated with a single task. Because it is abstract, you do not use this class directly but instead subclass or use one of the system-defined subclasses (NSInvocationOperation or NSBlockOperation) to perform the actual task.
并发执行你需要重载如下4个方法
//执行任务主函数,线程运行的入口函数
-(void)start
//是否允许并发,返回YES,允许并发,返回NO不允许。默认返回NO
-(BOOL)isConcurrent
- (BOOL)isExecuting
//是否已经完成,这个必须要重载,不然放在放在NSOperationQueue里的NSOpertaion不能正常释放。
- (BOOL)isFinished
比如TestNSOperation:NSOperaion 重载上述的4个方法,
声明一个NSOperationQueue,
NSOperationQueue *queue = [[[NSOperationQueue alloc ] init]autorelease];
[queue addOperation:testNSoperation];
它会自动调用TestNSOperation里的start函数,如果需要多个NSOperation,你需要设置queue的一些属性,如果多个NSOperation之间有依赖关系,也可以设置,具体可以参考API文档。
(2)非并发执行
-(void)main
只需要重载这个main方法就可以了。
dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
async表明异步运行,block代表的是你要做的事情,queue则是你把任务交给谁来处理了.
之所以程序中会用到多线程是因为程序往往会需要读取数据,然后更新UI.为了良好的用户体验,读取数据的操作会倾向于在后台运行,这样以避免阻塞主线程.GCD里就有三种queue来处理。
GCD
1. Main queue:
顾名思义,运行在主线程,由dispatch_get_main_queue获得.和ui相关的就要使用MainQueue.
2.Serial quque(private dispatch queue)
每次运行一个任务,可以添加多个,执行次序FIFO. 通常是指程序员生成的.
3. Concurrent queue(globaldispatch queue):
可以同时运行多个任务,每个任务的启动时间是按照加入queue的顺序,结束的顺序依赖各自的任务.使用dispatch_get_global_queue获得.
所以我们可以大致了解使用GCD的框架:
dispatch_async(getDataQueue,^{
//获取数据,获得一组后,刷新UI.
dispatch_aysnc(mainQueue, ^{
//UI的更新需在主线程中进行
};
})
总结一下这三种多线程方式的区别:
Thread
是这三种范式里面相对轻量级的,但也是使用起来最负责的,你需要自己管理thread的生命周期,线程之间的同步。线程共享同一应用程序的部分内存空间,
它们拥有对数据相同的访问权限。你得协调多个线程对同一数据的访问,一般做法是在访问之前加锁,这会导致一定的性能开销。在 iOS
中我们可以使用多种形式的 thread:
Cocoa threads: 使用NSThread 或直接从 NSObject 的类方法
performSelectorInBackground:withObject: 来创建一个线程。如果你选择thread来实现多线程,那么
NSThread 就是官方推荐优先选用的方式。
Cocoa operations是基于 Obective-C实现的,类 NSOperation 以面向对象的方式封装了用户需要执行的操作,我们只要聚焦于我们需要做的事情,而不必太操心线程的管理,同步等事情,因为NSOperation已经为我 们封装了这些事情。 NSOperation 是一个抽象基类,我们必须使用它的子类。iOS 提供了两种默认实现:NSInvocationOperation 和 NSBlockOperation。
Grand Central Dispatch (GCD): iOS4 才开始支持,它提供了一些新的特性,以及运行库来支持多核并行编程,它的关注点更高:如何在多个 cpu 上提升效率。
最后,既然说道多线程的开发,难免会在多线程之间进行通讯;
利用NSObject的一些类方法,可以轻松搞定。
在应用程序主线程中做事情:
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array
在指定线程中做事情:
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array
在当前线程中做事情:
//Invokes a method of the receiver on the current thread using the default mode after a delay. - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay performSelector:withObject:afterDelay:inModes:
取消发送给当前线程的某个消息
cancelPreviousPerformRequestsWithTarget: cancelPreviousPerformRequestsWithTarget:selector:object:
示例:
1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 2 { 3 self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; 4 5 //创建线程的第一种方式 6 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"universe"]; 7 [thread start]; 8 [thread release]; 9 10 11 //创建线程的第二种方式,NSThread类方法 12 [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"yuzhou"]; 13 14 15 //创建线程的第三种方法 NSObject方法 16 [self performSelectorInBackground:@selector(run:) withObject:@"nsobject thread"]; 17 18 //创建线程的第四种方式 19 NSOperationQueue *oprationQueue = [[NSOperationQueue alloc] init]; 20 [oprationQueue addOperationWithBlock:^{ 21 //这个block语句块在子线程中执行 22 NSLog(@"oprationQueue"); 23 }]; 24 [oprationQueue release]; 25 26 //第五种创建线程的方式 27 NSOperationQueue *oprationQueue1 = [[NSOperationQueue alloc] init]; 28 oprationQueue1.maxConcurrentOperationCount = 1;//指定池子的并发数 29 30 //NSOperation 相当于java中的runnable接口,继承自它的就相当一个任务 31 NSInvocationOperation *invation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run:) object:@"invation"]; 32 [oprationQueue1 addOperation:invation];//将任务添加到池子里面,可以给池子添加多个任务,并且指定它的并发数 33 [invation release]; 34 35 //第二个任务 36 NSInvocationOperation *invation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run2:) object:@"invocation2"]; 37 invation2.queuePriority = NSOperationQueuePriorityHigh;//设置线程优先级 38 [oprationQueue1 addOperation:invation2]; 39 [invation2 release]; 40 41 [oprationQueue1 release]; 42 43 //调用主线程,用来子线程和主线程交互,最后面的那个boolean参数,如果为yes就是等这个方法执行完了在执行后面的代码;如果为no的话,就是不管这个方法执行完了没有,接着往下走 44 [self performSelectorOnMainThread:@selector(onMain) withObject:self waitUntilDone:YES]; 45 46 //---------------------GCD----------------------支持多核,高效率的多线程技术 47 //创建多线程第六种方式 48 dispatch_queue_t queue = dispatch_queue_create("name", NULL); 49 //创建一个子线程 50 dispatch_async(queue, ^{ 51 // 子线程code... .. 52 NSLog(@"GCD多线程"); 53 54 //回到主线程 55 dispatch_sync(dispatch_get_main_queue(), ^{//其实这个也是在子线程中执行的,只是把它放到了主线程的队列中 56 Boolean isMain = [NSThread isMainThread]; 57 if (isMain) { 58 NSLog(@"GCD主线程"); 59 } 60 }); 61 }); 62 63 64 self.window.backgroundColor = [UIColor whiteColor]; 65 [self.window makeKeyAndVisible]; 66 return YES; 67 } 68 69 - (void)onMain 70 { 71 Boolean b = [NSThread isMainThread]; 72 if (b) { 73 NSLog(@"onMain;;%d",b); 74 } 75 } 76 77 78 - (void) run:(NSString*)str 79 { 80 NSLog(@"多线程运行:::%@",str); 81 } 82 - (void) run2:(NSString*)str 83 { 84 NSLog(@"多线程运行:::%@",str); 85 }