一個NSThread對象就代表一條線程
創建、啟動線程
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 // 創建并開啟一條子線程 4 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"參數"]; 5 // 線程一啟動,就會在線程thread中執行self的run方法 6 [thread start]; 7 } 8 /** 9 * 開啟子線程10 *11 * @param param object傳進來的參數12 */13 - (void)run:(NSString *)param14 {15 NSLog(@"currentThread:%@--run--%@", [NSThread currentThread], param);16 }17 18 打印結果:19 <NSThread: 0x7fd5b2f207f0>{number = 2, name = (null)}--run--參數
主線程相關用法
1 + (NSThread *)mainThread; // 獲得主線程2 - (BOOL)isMainThread; // 是否為主線程3 + (BOOL)isMainThread; // 是否為主線程
其他用法
獲得當前線程NSThread *current = [NSThread currentThread];線程的調度優先級+ (double)threadPRiority;+ (BOOL)setThreadPriority:(double)p;- (double)threadPriority;- (BOOL)setThreadPriority:(double)p;調度優先級的取值范圍是0.0 ~ 1.0,默認0.5,值越大,優先級越高線程的名字- (void)setName:(NSString *)n;- (NSString *)name;
其他創建線程方式
創建線程后自動啟動線程[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];隱式創建并啟動線程[self performSelectorInBackground:@selector(run) withObject:nil];
上述2種創建線程方式的優缺點
啟動線程- (void)start; // 進入就緒狀態 -> 運行狀態。當線程任務執行完畢,自動進入死亡狀態阻塞(暫停)線程+ (void)sleepUntilDate:(NSDate *)date;+ (void)sleepForTimeInterval:(NSTimeInterval)ti;// 進入阻塞狀態強制停止線程+ (void)exit;// 進入死亡狀態
注意:一旦線程停止(死亡)了,就不能再次開啟任務
互斥鎖使用格式:@synchronized(鎖對象) { // 需要鎖定的代碼 }
注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的
互斥鎖的優缺點
互斥鎖的使用前提:多條線程搶奪同一塊資源
相關專業術語:線程同步
線程同步的意思是:多條線程按順序地執行任務
互斥鎖,就是使用了線程同步技術
OC在定義屬性時有nonatomic和atomic兩種選擇
atomic加鎖原理
1 @property (assign, atomic) int age;2 3 - (void)setAge:(int)age4 {5 @synchronized(self) {6 _age = age;7 }8 }
nonatomic和atomic對比
線程間通信的體現
1個線程傳遞數據給另1個線程
在1個線程中執行完特定任務后,轉到另1個線程繼續執行任務
線程間通信常用方法:
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
全稱是Grand Central Dispatch,純C語言,提供了非常多強大的函數。
GCD的優勢
GCD中有2個核心概念
將任務添加到隊列中:
GCD中有2個用來執行任務的函數
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
同步和異步的區別
GCD的隊列可以分為2大類型
GCD默認已經提供了全局的并發隊列,供整個應用使用,不需要手動創建
使用dispatch_get_global_queue函數獲得全局的并發隊列
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority, // 隊列的優先級unsigned long flags); // 此參數暫時無用,用0即可dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 獲得全局并發隊列
全局并發隊列的優先級
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(中)#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺
GCD中獲得串行有2種途徑
使用dispatch_queue_create函數創建串行隊列
dispatch_queue_tdispatch_queue_create(const char *label, // 隊列名稱 dispatch_queue_attr_t attr); // 隊列屬性,一般用NULL即可dispatch_queue_t queue = dispatch_queue_create("queue", NULL); // 創建dispatch_release(queue); // 非ARC需要釋放手動創建的隊列
使用主隊列(跟主線程相關聯的隊列)
主隊列是GCD自帶的一種特殊的串行隊列
放在主隊列中的任務,都會放到主線程中執行
使用dispatch_get_main_queue()獲得主隊列
dispatch_queue_t queue = dispatch_get_main_queue();
從子線程回到主線程
1 dispatch_async(2 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{3 // 執行耗時的異步操作...4 dispatch_async(dispatch_get_main_queue(), ^{5 // 回到主線程,執行UI刷新操作6 });7 });
iOS常見的延時執行有2種方式
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];// 2秒后再調用self的run方法
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后異步執行這里的代碼...});
使用dispatch_once函數能保證某段代碼在程序運行過程中只被執行1次
1 static dispatch_once_t onceToken;2 dispatch_once(&onceToken, ^{3 // 只執行1次的代碼(這里面默認是線程安全的)4 });
有這么1種需求
首先:分別異步執行2個耗時的操作
其次:等2個異步操作都執行完畢后,再回到主線程執行操作
如果想要快速高效地實現上述需求,可以考慮用隊列組
1 dispatch_group_t group = dispatch_group_create(); 2 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 3 // 執行1個耗時的異步操作 4 }); 5 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 6 // 執行1個耗時的異步操作 7 }); 8 dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 9 // 等前面的異步操作都執行完畢后,回到主線程...10 });
單例模式可以保證在程序運行過程,一個類只有一個實例,而且該實例易于供外界訪問。從而方便地控制了實例個數,并節約系統資源。
單例模式在ARC/MRC環境下的寫法有所不同,需要編寫2套不同的代碼
可以用宏判斷是否為ARC環境
#if __has_feature(objc_arc)// ARC#else// MRC#endif
ARC中,單例模式的實現:
1. 在.m中保留一個全局的static的實例
static id _instance;
2. 重寫allocWithZone:方法,在這里創建唯一的實例(注意線程安全)
1 + (id)allocWithZone:(struct _NSZone *)zone2 {3 @synchronized(self) {4 if (!_instance) {5 _instance = [super allocWithZone:zone];6 }7 }8 return _instance;9 }
3. 提供1個類方法讓外界訪問唯一的實例
1 + (instancetype)sharedSoundTool2 {3 @synchronized(self) {4 if (!_instance) {5 _instance = [[self alloc] init];6 }7 }8 return _instance;9 }
非ARC中(MRC),單例模式的實現(比ARC多了幾個步驟)
1. 實現copyWithZone:方法
1 + (id)copyWithZone:(struct _NSZone *)zone2 {3 return _instance;4 }
2. 實現內存管理方法
1 - (id)retain { return self; }2 - (NSUInteger)retainCount { return 1; }3 - (oneway void)release {}4 - (id)autorelease { return self; }
NSOperation的作用:
配合使用NSOperation和NSOperationQueue也能實現多線程編程
NSOperation和NSOperationQueue實現多線程的具體步驟:
NSOperation是個抽象類,并不具備封裝操作的能力,必須使用它的子類
使用NSOperation子類的方式有3種
NSInvocationOperation
創建NSInvocationOperation對象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
調用start方法開始執行操作
- (void)start;
一旦執行操作,就會調用target的sel方法
注意:
NSBlockOperation
創建NSBlockOperation對象
+ (id)blockOperationWithBlock:(void (^)(void))block;
通過addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
注意:只要NSBlockOperation封裝的操作數 > 1,就會異步執行操作
NSOperationQueue的作用:NSOperation可以調用start方法來執行任務,但默認是同步執行的。如果將NSOperation添加到NSOperationQueue(操作隊列)中,系統會自動異步執行NSOperation中的操作。
添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;- (void)addOperationWithBlock:(void (^)(void))block;
并發數也就是同時執行的任務數。比如,同時開3個線程執行3個任務,并發數就是3。
最大并發數的相關方法
- (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
取消隊列的所有操作
- (void)cancelAllOperations;
也可以調用NSOperation的- (void)cancel方法取消單個操作
暫停和恢復隊列
- (void)setSuspended:(BOOL)b; // YES代表暫停隊列,NO代表恢復隊列- (BOOL)isSuspended;
設置NSOperation在queue中的優先級,可以改變操作的執行順序
- (NSOperationQueuePriority)queuePriority;- (void)setQueuePriority:(NSOperationQueuePriority)p;
優先級的取值(優先級越高,越先執行)
NSOperationQueuePriorityVeryLow = -8L,NSOperationQueuePriorityLow = -4L,NSOperationQueuePriorityNormal = 0,NSOperationQueuePriorityHigh = 4,NSOperationQueuePriorityVeryHigh = 8
NSOperation之間可以設置依賴來保證執行順序,比如一定要讓操作A執行完后,才能執行操作B,可以這么寫:
[operationB addDependency:operationA]; // 操作B依賴于操作A
可以在不同queue的NSOperation之間創建依賴關系
注意:不能相互依賴,比如A依賴B,B依賴A
對于添加到queue中的operations,它們的執行順序取決于2點:
因此,總體的執行順序是:先滿足依賴關系,然后再從NSOperation中選擇優先級最高的那個執行
自定義NSOperation的步驟很簡單
重寫- (void)main方法,在里面實現想執行的任務
重寫- (void)main方法的注意點
|
新聞熱點
疑難解答