iOS有三種多線程技術:
- 1.NSThread
- 創建方式兩種:
- 1.實例方法:
- - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
- 先創建線程對象,然后再運行線程操作,在運行線程操作前可以設置線程的優先級等線程信息
- 2.類方法:
- + (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
- 直接創建線程並開始運行線程
- 使用范例:
- [NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
- NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil];
- [myThread start];
- 參數解釋:
- selector :線程執行的方法,這個selector只能有一個參數,而且不能有返回值。
- target :selector消息發送的對象
- argument:傳輸給target的唯一參數,也可以是nil
- 不顯示創建線程的方法:
- 調用NSObject的類方法performSelectorInBackground:withObject: 默認在子線程中執行
- 示范:
- [Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
- 示范例子:(子線程異步下載,主線程UI更新)
- 創建方式兩種:
#import "ViewController.h" #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL]; NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL]; [thread start]; } -(void)downloadImage:(NSString *) url{ NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]]; UIImage *image = [[UIImage alloc]initWithData:data]; if(image == nil){ }else{ [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];//在主線程中執行(線程間通訊) } } -(void)updateUI:(UIImage*) image{ self.imageView.image = image; } @end
- 2.NSOperation
- 用以封裝執行程序中獨立的工作單元,提供異步執行機制。
- NSOperation類為抽象類,基於模版方法設計模式
- Operations可以獨立運行,也可以與Operation Queue協同運行。
- 使用方式有兩種:
- 1.用定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。
- NSInvocationOperation:
- 創建方式:
- NSInvocationOperation* operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(customTaskMethod:)object:params];
- NSBlockOperation:
- 創建方式:
- NSBlockOperation* blockOperation = [NSBlockOperation blockOperationWithBlock: ^{
- // to do the task.
- }];
- 在創建blockOperation后可以調用addExecutionBlock:方法添加更多的block
- 示范例子:
#import "ViewController.h" #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL]; NSOperationQueue *queue = [[NSOperationQueue alloc]init]; [queue addOperation:operation]; // Do any additional setup after loading the view, typically from a nib. } -(void)downloadImage:(NSString *)url{ NSLog(@"url:%@", url); NSURL *nsUrl = [NSURL URLWithString:url]; NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl]; UIImage * image = [[UIImage alloc]initWithData:data]; [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES]; } -(void)updateUI:(UIImage*) image{ self.imageView.image = image; }
-
-
- 2.繼承NSOperation
- 1.提供一個自定義的初始化方法,在執行operation之前提供初始化流程,准備operation狀態
- 2.只需繼承重寫NSOperation的一個方法main
- 3.然后把NSOperation子類的對象放入NSOperationQueue隊列中,該隊列就會啟動並開始處理它
- 示范例子:
- 2.繼承NSOperation
-
@interface MoveFileOperation : NSOperation - (id)initWithSrcURL:(NSURL *)srcURL toDestinationURL:(NSURL*)desURL; @end // MoveFileOperation.m @interface MoveFileOperation () @property (retain) NSURL *srcURL; @property (retain) NSURL *desURL; @end @implementation MoveFileOperation @synthesize rootURL, queue; - (id)initWithSrcURL:(NSURL *)srcURL toDestinationURL:(NSURL*)desURL; { self = [super init]; if (self) { self.srcURL = srcURL; self.desURL = desURL; } return self; } - (void)main { if ([self isCancelled]){ return; } NSDirectoryEnumerator *itr =[[NSFileManager defaultManager] enumeratorAtURL:self.srcURL includingPropertiesForKeys:nil options:(NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsPackageDescendants) errorHandler:nil]; NSError *error = [NSError new]; for (NSURL *url in itr) { if ([self isCancelled]) {// break; }else{ NSString *fileName = [url lastPathComponent]; NSURL *desFileURL = [self.desURL URLByAppendingPathComponent:fileName]; [[NSFileManager defaultManager] copyItemAtURL:url toURL:desFileURL error:&error]; } } }
-
-
-
- 通過isCancelled方法對operation支持線程取消行為:
- 常見的正確調用isCancelled的位置包括:
- 1.在實際執行工作之前
- 2.在每個循環的執行體中,如果一次執行體耗時很長可酌情添加調用次數
- 3.程序相對容易終止的代碼處。
- 配置operation的依賴關系:
- 調用addDependency: 方法可以建立兩個operation對象間的依賴關系:
- 這個單向關系表明當前operation對象只有在目標operation對象執行完成之后才能執行。
- operation對象的依賴關系不限於同一個操作隊列。
- 有依賴關系的operation對象可以添加到不同的操作隊列中。
- 但是operation之間不能添加循環依賴關系。
- 添加Completion Block:
- 通過setCompletionBlock: 方法可以完成添加completion block的工作,可以在此處派發operation完成的消息。
- 執行operation的方式:
- 1 .將operation對象添加到操作隊列NSOperatinQueue對象中:
- NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
- 1.// Add a single operation
- [aQueue addOperation:anOp];
- 2.// Add multiple operations
- [aQueue addOperations:anArrayOfOps waitUntilFinished:NO];
- 3.// Add a block
- [aQueue addOperationWithBlock:^{
- /* Do something. */
- }];
- NSOperationQueue設計上是用來並發執行operation,setMaxConcurrentOperationCount:方法可以設置操作隊列並行執行的最大數量。
- 需要設置operation間的依賴關系來保證它們的執行順序是你想要的。
- 2.手動執行operation:
- 一個operation只有在其isReady方法返回YES時才被認為是可運行的。
- isReady方法會被整合進NSOperation的依賴管理系統來保證operation的依賴狀態。
- 只有在依賴關系清楚后,operation才開始運行。
- 手動執行operation時,必須調用其start方法。
- 1 .將operation對象添加到操作隊列NSOperatinQueue對象中:
- 取消operation:
- 一旦加入操作隊列,操作隊列就擁有了該operation,並且它不能被刪除。
- 調出operation的唯一方法是取消(cancel)它
- 在一個operation上調用cancel可以取消其執行,在操作隊列對象上調用cancelAllOperations 會取消所有operation。
- operation的取消行為也會被認為是執行完畢(finished),依賴於它的其它operation對象會收到KVO通知來清除該依賴關系。
- 等待operation結束:
- 如果創建operation的進程需要處理operation的結果,可以使用NSOperation的 waitUntilFinished方法來阻塞代碼直到operation完成(決不能在主線程上等待一個operation結束)
- 掛起和回復隊列:
- 調用NSOperationQueue對象的setSuspended: 方法可以操作隊列掛起。掛起隊列不會阻礙當前正在執行中的operation,它只是阻止新的operation的執行。
-
-
- 3.GCD