1祭往、一個(gè)NSThread對(duì)象就代表一條線程
創(chuàng)建驮肉、啟動(dòng)線程
NSThread *thread = [[NSThread alloc] initWithTarget:self start];selector:@selector(run) object:nil];
[thread
// 線程一啟動(dòng)已骇,就會(huì)告訴 CPU 準(zhǔn)備就緒,可以隨時(shí)接受 CPU 調(diào)度! CPU 調(diào)度當(dāng)前線程之后,就會(huì)在線程thread中執(zhí)行self的run方法
主線程相關(guān)用法
- (NSThread *)mainThread; // 獲得主線程
- (BOOL)isMainThread; // 是否為主線程
- (BOOL)isMainThread; // 是否為主線程
2褪储、獲得當(dāng)前線程
NSThread *current = [NSThread currentThread];
線程的調(diào)度優(yōu)先級(jí)
- (double)threadPriority;
- (BOOL)setThreadPriority:(double)p;
- (double)threadPriority;
- (BOOL)setThreadPriority:(double)p;
- 調(diào)度優(yōu)先級(jí)的取值范圍是0.0 ~ 1.0,默認(rèn)0.5浪读,值越大,優(yōu)先級(jí)越高
線程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
三碘橘、創(chuàng)建線程后自動(dòng)啟動(dòng)線程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
隱式創(chuàng)建并啟動(dòng)線程
[self performSelectorInBackground:@selector(run) withObject:nil];
上述2種創(chuàng)建線程方式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):簡(jiǎn)單快捷
缺點(diǎn):無法對(duì)線程進(jìn)行更詳細(xì)的設(shè)置
四、互斥鎖使用格式
@synchronized(鎖對(duì)象) { // 需要鎖定的代碼 }
注意:鎖定1份代碼只用1把鎖仰禽,用多把鎖是無效的
互斥鎖的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):能有效防止因多線程搶奪資源造成的數(shù)據(jù)安全問題
缺點(diǎn):需要消耗大量的CPU資源
互斥鎖的使用前提:多條線程搶奪同一塊資源
相關(guān)專業(yè)術(shù)語(yǔ):線程同步
線程同步的意思是:多條線程在同一條線上執(zhí)行(按順序地執(zhí)行任務(wù))
互斥鎖错负,就是使用了線程同步技術(shù)
五、OC在定義屬性時(shí)有nonatomic和atomic兩種選擇
-
atomic:原子屬性,為setter方法加鎖(默認(rèn)就是atomic)
nonatomic:非原子屬性识颊,不會(huì)為setter方法加鎖
-
nonatomic和atomic對(duì)比
atomic:線程安全奕坟,需要消耗大量的資源
nonatomic:非線程安全,適合內(nèi)存小的移動(dòng)設(shè)備
-
iOS開發(fā)的建議
所有屬性都聲明為nonatomic
盡量避免多線程搶奪同一塊資源
盡量將加鎖月杉、資源搶奪的業(yè)務(wù)邏輯交給服務(wù)器端處理,減小移動(dòng)客戶端的壓力
六桨昙、既然多線程這么爽, 線程是不是越多越好呢?
<1> 開啟線程需要消耗一定的內(nèi)存(默認(rèn)情況下,線程占用 512KB 的棧區(qū)空間);
<2> 會(huì)使應(yīng)用程序增加很多代碼!代碼變多之后,程序復(fù)雜性就會(huì)提高!
<3> CPU 在多條線程之間來回切換!線程越多, CPU就越累!
建議: 在移動(dòng)應(yīng)用的開發(fā)中; 一般只開3~5條線程!
七腌歉、重點(diǎn):為什么要使用橋接?你是怎么進(jìn)行混合開發(fā)的?
{
橋接 (__bridge) :C 和 OC 之間傳遞數(shù)據(jù)的時(shí)候需要使用橋接! why?為什么呢?
1.內(nèi)存管理:
在 OC 中,如果是在 ARC環(huán)境下開發(fā),編譯器在編譯的時(shí)候會(huì)根據(jù)代碼結(jié)構(gòu),自動(dòng)為 OC 代碼添加 retain/release/autorelease等. ----->自動(dòng)內(nèi)存管理(ARC)的原理!
但是, ARC只負(fù)責(zé) OC 部分的內(nèi)存管理!不會(huì)負(fù)責(zé) C 語(yǔ)言部分代碼的內(nèi)存管理!
也就是說!即使是在 ARC 的開發(fā)環(huán)境中!如果使用的 C 語(yǔ)言代碼出現(xiàn)了 retain/copy/new/create等字樣呢!我們都需要手動(dòng)為其添加 release 操作!否則會(huì)出現(xiàn)內(nèi)存泄露!
在混合開發(fā)時(shí)(C 和 OC 代碼混合),C 和 OC 之間傳遞數(shù)據(jù)需要使用 __bridge 橋接,目的就是為了告訴編譯器如何管理內(nèi)存
在 MRC中不需要使用橋接! 因?yàn)槎夹枰謩?dòng)進(jìn)行內(nèi)存管理!
2.數(shù)據(jù)類型轉(zhuǎn)換:
Foundation 和 Core Foundation框架的數(shù)據(jù)類型可以互相轉(zhuǎn)換的
Foundation : OC
Core Foundation : C語(yǔ)言
NSString *str = @"123"; // Foundation
CFStringRef str2 = (__bridge CFStringRef)str; // Core Foundation
NSString *str3 = (__bridge NSString *)str2;
CFArrayRef ---- NSArray
CFDictionaryRef ---- NSDictionary
CFNumberRef ---- NSNumber
Core Foundation中手動(dòng)創(chuàng)建的數(shù)據(jù)類型翘盖,都需要手動(dòng)釋放
CGPathRef path = CGPathCreateMutable();
CGPathRetain(path);
CGPathRelease(path);
CGPathRelease(path);
3.橋接的添加:
利用 Xcode 提示自動(dòng)添加! --簡(jiǎn)單/方便/快速
/**
凡是函數(shù)名中帶有create\copy\new\retain等字眼, 都應(yīng)該在不需要使用這個(gè)數(shù)據(jù)的時(shí)候進(jìn)行release
GCD的數(shù)據(jù)類型在ARC環(huán)境下不需要再做release
CF(Core Foundation)的數(shù)據(jù)類型在ARC\MRC環(huán)境下都需要再做release
*/
}
八馍驯、iOS中多線程實(shí)現(xiàn)方案2.NSThread - 1基本使用
重點(diǎn):1.三種創(chuàng)建線程! 2.常用方法!
{
1.NSThread: 一個(gè) NSThread 就代表一個(gè)線程對(duì)象!
// OC語(yǔ)言 / 使用面向?qū)ο?/ 需要手動(dòng)管理線程生命周期(創(chuàng)建/銷毀等)
2.三種多線程實(shí)現(xiàn)方案:
1> 先創(chuàng)建陶舞,后啟動(dòng)
// 創(chuàng)建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:nil];
// 啟動(dòng)
[thread start];
2> 創(chuàng)建完自動(dòng)啟動(dòng)
[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:nil];
3> 隱式創(chuàng)建(自動(dòng)啟動(dòng))
[self performSelectorInBackground:@selector(download:) withObject:nil];
3.常用方法:
名字/獲得主線程/獲得當(dāng)前線程/阻塞線程/退出線程
// 不常用: 棧區(qū)大小/優(yōu)先級(jí)
1> 獲得當(dāng)前線程
+ (NSThread *)currentThread;
2> 獲得主線程
+ (NSThread *)mainThread;
3> 睡眠(暫停)線程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
4> 設(shè)置線程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
}
九、重點(diǎn):1.線程同步技術(shù)! 2.理解資源共享
{
當(dāng)多條線程訪問同一塊資源的時(shí)候,就會(huì)出現(xiàn)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全的問題!
1.ATM機(jī)取錢; 賣票;
2.解決方案:互斥鎖 @synchronized(鎖對(duì)象self){ /*需要鎖住的代碼,越少越好!*/ } ------- 廁所加鎖!
注意:鎖定一份代碼只用一把鎖,用多把鎖是無效的!
優(yōu)點(diǎn):能有效防止因多線程搶奪資源而引起的數(shù)據(jù)安全問題!
缺點(diǎn):需要消耗大量的CPU資源!
結(jié)論:盡量少加鎖!互斥鎖的使用前提是多條線程搶奪同一塊資源!
3.添加互斥鎖技巧: [[NSUserDefaults standardUserDefaults] synchronize];
4.線程同步技術(shù): ----- 互斥鎖使用了線程同步技術(shù)!
多條線程在同一條線上按順序執(zhí)行任務(wù)!
5.線程安全:保證多條線程進(jìn)行讀寫操作,都能夠得到正確的結(jié)果!
用 '鎖' 來實(shí)現(xiàn)線程安全!
}
十、為什么要在主線程更新UI?
因?yàn)閁IKit 框架都不是線程安全的!為了得到更好的用戶體驗(yàn),UIKit框架犧牲了線程安全;
所以我們要在主線程更新UI;
十一菩佑、下載圖片 更新 UI
/*------------------------- iOS中多線程實(shí)現(xiàn)方案2.NSThread - 4線程間通信 -------------------------*/
1.下載圖片? 更新 UI?
{
1.后臺(tái)線程(子線程)下載圖片;
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
2.主線程更新 UI.
線程間通信常用方法:
// 最后一個(gè)參數(shù):是否等待調(diào)用方法執(zhí)行結(jié)束!
<1>[self performSelectorOnMainThread:@selector(setImageWithImage:) withObject:nil waitUntilDone:YES];
<2>[self performSelector:@selector(setImageWithImage:) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];
}