多線程的概括
- iOS有三種多線程編程的技術余黎,分別是:NSThread,Cocoa NSOperation,GCD這三種編程方式從上到下颖侄,抽象度層次是從低到高的鸟雏,抽象度越高的使用越簡單。
NSThread
-
需要自己管理線程的生命周期(向?qū)ο笠粯?
ARC下不用自己管理
览祖,線程同步時線程同步對數(shù)據(jù)的加鎖會有一定的系 統(tǒng)開銷孝鹊。//常用兩個方法,一個對象方法需創(chuàng)建NSThread穴墅,一個類方法惶室。 - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument + (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];
// NSObject 的方法創(chuàng)建并自動啟動
[self performSelectorInBackground:@selector(run:) withObject:nil];
-
NSThread的其他方法
//取消線程 - (void)cancel; //啟動線程 - (void)start; //判斷某個線程的狀態(tài)的屬性 @property (readonly, getter=isExecuting) BOOL executing; @property (readonly, getter=isFinished) BOOL finished; @property (readonly, getter=isCancelled) BOOL cancelled; //設置和獲取線程名字 -(void)setName:(NSString *)n; -(NSString *)name; //獲取當前線程信息 + (NSThread *)currentThread; //獲取主線程信息 + (NSThread *)mainThread; //使當前線程暫停一段時間,或者暫停到某個時刻 + (void)sleepForTimeInterval:(NSTimeInterval)time; + (void)sleepUntilDate:(NSDate *)date;
2. NSOperation
- 不需要關心線程管理(創(chuàng)建多少個線程)玄货,數(shù)據(jù)同步(鎖的問題)的事情皇钞,精力放在自己需要執(zhí)行的操作上,然后把操作放在隊列里
2.1NSOperation
創(chuàng)建NSBlockOperation對象
- 單個操作創(chuàng)建后松捉,單個操作里面再添加block的時候夹界,block會在其他線程上執(zhí)行
let operation = NSBlockOperation { () -> Void inprint(NSThread.currentThread())
}
operation.addExecutionBlock { () -> Void inprint("execution block1 -- \(NSThread.currentThread())")
}
operation.start()
來源: https://bestswifter.com/multithreadconclusion/
<NSThread: 0x7f89b1c070f0>{number = 1, name = main}
execution block1 -- <NSThread: 0x7f89b1e17030>{number = 2, name = (null)}
>注意;NSBlockOperation 還有一個方法:addExecutionBlock: 隘世,通過這個方法可以給 Operation 添加多個執(zhí)行 Block可柿。這樣 Operation 中的任務 會并發(fā)執(zhí)行,它會 在主線程和其它的多個線程 執(zhí)行這些任務丙者,
創(chuàng)建NSInvocationOperation對象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
單個操作的需要調(diào)用start開始
隊列
把操作放在隊列中會自動調(diào)用任務的 start() 方法
-
主隊列
- 凡是添加到主隊列中的任務(NSOperation)复斥,都會放到主線程中執(zhí)行。
NSOperationQueue *queue = [NSOperationQueue mainQueue];//1.獲取主隊列械媒,串行隊列
//2.創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
[queue addOperation:operation];3.隊列添加任務
- 其他隊列(其他隊列的任務會在其他線程并行執(zhí)行目锭。)
//1.創(chuàng)建一個其他隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//2.創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//3.添加多個Block
for (NSInteger i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}
//4.隊列添加任務
[queue addOperation:operation];
2017-07-28 20:26:28.463 test[18622:4443534] <NSThread: 0x7fd022c3ac10>{number = 5, name = (null)}
2017-07-28 20:26:28.463 test[18622:4443536] 第2次 - <NSThread: 0x7fd022e36d50>{number = 2, name = (null)}
2017-07-28 20:26:28.463 test[18622:4443535] 第0次 - <NSThread: 0x7fd022f237f0>{number = 4, name = (null)}
2017-07-28 20:26:28.463 test[18622:4443533] 第1次 - <NSThread: 0x7fd022d372b0>{number = 3, name = (null)}
2017-07-28 20:26:28.463 test[18622:4443534] 第3次 - <NSThread: 0x7fd022c3ac10>{number = 5, name = (null)}
2017-07-28 20:26:28.463 test[18622:4443536] 第4次 - <NSThread: 0x7fd022e36d50>{number = 2, name = (null)}
- 另外一種利用隊列的方法,直接添加block纷捞,不需要新建操作痢虹。
- (void)addOperationWithBlock:(void (^)(void))block; //NSOperationQueu來調(diào)用
總結:.新建隊列(其他隊列),新建operation,將operation添加到隊列里(自動開線程不用管)不用調(diào)用start方法主儡。系統(tǒng)自動調(diào)用,設置隊列的并發(fā)數(shù)為1就是串行隊列奖唯。串行隊列任務一個接一個執(zhí)行。不設置隊列并發(fā)數(shù)就是并行隊列糜值。并行隊列任務一起執(zhí)行丰捷。
3.GCD
- Grand Central Dispatch是由蘋果開發(fā)的一個多核編程的解決方案坯墨,自動管理線程的生命周期(創(chuàng)建線程、調(diào)度任務瓢阴、銷毀線程)畅蹂。GCD是基于C語言的。
- GCD的工作原理是:讓程序平行排隊的特定任務荣恐,根據(jù)可用的處理資源,安排他們在任何可用的處理器核心上執(zhí)行任務累贤。
- 把block添加到隊列里即可叠穆。用異步(或者)同步函數(shù)處理這些。
隊列
-
主隊列
//OBJECTIVE-C dispatch_queue_t queue = dispatch_get_main_queue();
- 主隊列:這是一個特殊的 串行隊列臼膏。什么是主隊列硼被,大家都知道吧无切,它用于刷新 UI弊予,任何需要刷新 UI 的工作都要在主隊列執(zhí)行,所以一般耗時的任務都要放到別的線程執(zhí)行症革。
-
全局隊列(系統(tǒng)提供的并行隊列)
//OBJECTIVE-C dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- 全局隊列異步:操作會新建多個線程始鱼、操作無序執(zhí)行仔掸,隊列前如果有其他任務,會等待前面的任務完成之后再執(zhí)行
- 全局隊列同步:操作不會新建線程医清、操作順序執(zhí)行
-
創(chuàng)建隊列
//OBJECTIVE-C //串行隊列 dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL); dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL); //并行隊列 dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
操作
-
同步操作:
- 串行隊列同步:操作不會新建線程起暮、操作順序執(zhí)行
- 并行隊列同步:操作不會新建線程、操作順序執(zhí)行
dispatch_sync(<#queue#>, ^{ //code here NSLog(@"%@", [NSThread currentThread]); });
-
異步操作
- 串行隊列異步:操作需要一個子線程会烙,會新建線程负懦、線程的創(chuàng)建和回收不需要程序員參與,操作順序執(zhí)行柏腻,“最安全的選擇”
- 并行隊列異步:操作會新建多個線程(有多少任務纸厉,就開n個線程執(zhí)行)、操作無序執(zhí)行五嫂;隊列前如果有其他任務颗品,會等待前面的任務完成之后再執(zhí)行;場景:既不影響主線程贫导,又不需要順序執(zhí)行的操作抛猫!
dispatch_async(<#queue#>, ^{ //code here NSLog(@"%@", [NSThread currentThread]); });