一、线程的使用
以向网络请求一张图片为例
-(void)downURL:(NSURL *)aURL { NSData *d = [NSData dataWithContentsOfURL:aURL]; UIImage *img = [UIImage imageWithData:d]; //imgView.image = img; // 切换回主线程执行UI的操作 [imgView performSelectorOnMainThread:@selector(setImage:) withObject:img waitUntilDone:NO]; }
方法1:系统后台执行
[self performSelectorInBackground:@selector(downURL:) withObject:url];
方法2:利用C级的NSThread执行
[NSThread detachNewThreadSelector:@selector(downURL:) toTarget:self withObject:url]; // 分派线程执行一个方法,静态方法创建了线程,并开始执行 NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(downURL:) object:url]; [t1 start]; // 创建具体线程对象需要触发开始
方法3:利用OC级的NSOperation执行,此处使用的是NSOperation的子类NSInvocationOperation(或NSBlockOperation)去执行,因为NSOperation只是一个抽象类,不能直接实例化使用
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downURL:) object:url]; [op1 setQueuePriority:NSOperationQueuePriorityNormal] NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downURL:) object:url]; //[op1 start]; // 线程对象不放到队列中的话需要触发开始 queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 1; // 设置队列同时执行线程最大数 [queue addOperation:op1]; // 队列会自动打开线程 [queue addOperation:op2]; [op1 release]; [op2 release];
方法4:继承NSOperation自定义线程类,利用target-action机制
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
-(void)someMethod { BIDImageOperation *op = [[BIDImageOperation alloc] initWithTarget:self Selector:@selector(refreshUI:) URL:url1]; [op start]; // [op release]; } -(void)refreshUI:(UIImage *)aImg { [imgView performSelectorOnMainThread:@selector(setImage:) withObject:aImg waitUntilDone:NO]; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#import <Foundation/Foundation.h> @interface BIDImageOperation : NSOperation { NSString *_imgURL; id _target; SEL _action; } @property (nonatomic,retain) NSString *imgURL; @property (nonatomic,assign) id target; @property (nonatomic,assign) SEL action; -(id)initWithTarget:(id)aTarget Selector:(SEL)aSelector URL:(NSString *)aURL; @end ###################################### #import "BIDImageOperation.h" @implementation BIDImageOperation @synthesize imgURL = _imgURL,target = _target,action = _action; -(id)initWithTarget:(id)aTarget Selector:(SEL)aSelector URL:(NSString *)aURL { if (self = [super init]) { self.imgURL = aURL; self.target = aTarget; self.action = aSelector; } return self; } -(void)main { if ([self isCancelled]) { return; } NSURL *url = [NSURL URLWithString:self.imgURL]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *img = [UIImage imageWithData:data]; if ([self isCancelled]) { return; } [self.target performSelector:self.action withObject:img]; } @end
二、线程安全
以一个售票服务的程序为例
1.锁
-(void)someMethod { NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; t1.name = @"window1"; [t1 start]; NSThread *t2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; t2.name = @"window2"; [t2 start]; //[NSThread detachNewThreadSelector:@selector(saleTicket) toTarget:self withObject:nil]; } -(void)saleTicket { while (1) { [lock lock]; // 对可能出现互斥的变量设置部分进行锁定 if (count>0) { count = 100 - ticket; NSLog(@"%@ 卖出:%d 剩余:%d",[NSThread currentThread].name,ticket,count); ticket++; } else { [lock unlock]; break; } [lock unlock]; } }
2.取消
[op cancel];并不能将线程取消掉,因为该方法是建议关闭而已,除非线程里的main或调用的方法中有对这个建议做接受处理,如下
if ([self isCancelled]) // or if([op isCancelled]) { return; }
在dealloc方法中,自定义线程类的成员变量都应该添加[op cancel];,队列则需要添加[queue cancelAllOperations];来停止退出线程。