一.資源搶奪
2> 資源搶奪解決方案
@sychronized{ }
dispatch_barrier_async
NSLock NSCondition
dispatch_semaphore_wait
二.iOS多線程技術(shù)
3> 對(duì)比iOS中的多線程技術(shù)
3.1> pthread
pthread跨平臺(tái),使用難度大,需要手動(dòng)管理線程生命周期
pthread_create創(chuàng)建線程,傳參線程標(biāo)記,線程屬性,初始函數(shù),函數(shù)參數(shù)
3.2> NSThread
NSThread需要手動(dòng)管理線程生命周期和
3.3> GCD
3.4> NSOperation
GCD是純C語(yǔ)言的API,NSOperationQueue是基于GCD的OC版本封裝
3.2> GCD僅僅支持FIFO隊(duì)列乖篷,只可以設(shè)置隊(duì)列的優(yōu)先級(jí),而NSOperationQueue中的每一個(gè)任務(wù)都可以被重新設(shè)置優(yōu)先級(jí)(setQueuePriority:)响驴,從而實(shí)現(xiàn)不同操作的執(zhí)行順序調(diào)整
3.3> GCD不支持異步操作之間的依賴關(guān)系設(shè)置。如果某個(gè)操作的依賴另一個(gè)操作的數(shù)據(jù)撕蔼,使用NSOperationQueue能夠設(shè)置依賴按照正確的順序執(zhí)行操作(addDependency:)豁鲤。GCD則沒(méi)有內(nèi)建的依賴關(guān)系支持(只能通過(guò)Barrior和同步任務(wù)手動(dòng)實(shí)現(xiàn))。
3.4> NSOperationQueue方便停止隊(duì)列中的任務(wù)(cancelAllOperations, suspended),GCD不方便停止隊(duì)列中的任務(wù).
3.5> NSOperationQueue支持KVO鲸沮,可以監(jiān)測(cè)operation是否正在執(zhí)行(isExecuted)琳骡、是否結(jié)束(isFinished),是否取消(isCanceld)
3.6> GCD的執(zhí)行速度比NSOperationQueue快
3.7> NSOperationQueue可設(shè)置最大并發(fā)數(shù)量(節(jié)電),GCD具有dispatch_once(只執(zhí)行一次,單例)和dispatch_after(延遲執(zhí)行)功能
3.8> NSObject分類(perform)和NSThread遇到對(duì)象分配需要手動(dòng)內(nèi)存管理,手動(dòng)管理線程生命周期
3.9> NSThread查看線程
3.10> NSObject分類線程通信
4> 原子屬性
原子屬性采用的是"多讀單寫"機(jī)制的多線程策略
"多讀單寫"縮小了鎖范圍,比互斥鎖的性能好
規(guī)定只在主線程更新UI,就是因?yàn)槿绻诙嗑€程中更新,就需要給UI對(duì)象加鎖,防止資源搶占寫入錯(cuò)誤,但是這樣會(huì)降低UI交互的性能,所以ios設(shè)計(jì)讓所有UI對(duì)象都是非線程安全的(不加鎖),并規(guī)定只在主線程中更新UI,規(guī)避多線程搶占資源問(wèn)題
三.其他
5> 多線程優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
使應(yīng)用程序的響應(yīng)速度更快,用戶界面在進(jìn)行其他工作的同時(shí)仍始終保持活動(dòng)狀態(tài);
優(yōu)化任務(wù)執(zhí)行,適當(dāng)提高資源利用率(cpu, 內(nèi)存);
缺點(diǎn):
線程占用內(nèi)存空間,管理線程需要額外的CPU開(kāi)銷,開(kāi)啟大量線程,降低程序性能;
增加程序復(fù)雜度,如線程間通信,多線程的資源共享等;
1> 在多線程中使用通知需要注意什么問(wèn)題?
1.多線程的底層實(shí)現(xiàn)讼溺?
1>首先搞清楚什么是線程楣号、什么是多線程
2> Mach是第一個(gè)以多線程方式處理任務(wù)的系統(tǒng),因此多線程的底層實(shí)現(xiàn)機(jī)制是基于Mach的線程
3>開(kāi)發(fā)中很少用Mach級(jí)的線程怒坯,因?yàn)镸ach級(jí)的線程沒(méi)有提供多線程的基本特征炫狱,線程之間是獨(dú)立的
4>開(kāi)發(fā)中實(shí)現(xiàn)多線程的方案
C語(yǔ)言的POSIX接口:#include
OC的NSThread
C語(yǔ)言的GCD接口(性能最好,代碼更精簡(jiǎn))
OC的NSOperation和NSOperationQueue(基于GCD)
2.線程間怎么通信剔猿?
1> performSelector:onThread:withObject:waitUntilDone:
2> NSMachPort
3.網(wǎng)絡(luò)圖片處理問(wèn)題中怎么解決一個(gè)相同的網(wǎng)絡(luò)地址重復(fù)請(qǐng)求的問(wèn)題毕荐?
利用字典(圖片地址為key,下載操作為value)
4.用NSOpertion和NSOpertionQueue處理A,B,C三個(gè)線程,要求執(zhí)行完A,B后才能執(zhí)行C,怎么做艳馒?
//創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//創(chuàng)建3個(gè)操作
NSOperation *a = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@”operation1---“);
}];
NSOperation *b = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@”operation1---“);
}];
NSOperation *c = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@”operation1---“);
}];
//添加依賴
[c addDependency:a];
[c addDependency:b];
//執(zhí)行操作
[queue addOperation:a];
[queue addOperation:b];
[queue addOperation:c];
5.列舉cocoa中常見(jiàn)對(duì)幾種多線程的實(shí)現(xiàn),并談?wù)劧嗑€程安全的幾種解決辦法及多線程安全怎么控制?
1>只在主線程刷新訪問(wèn)UI
2>如果要防止資源搶奪弄慰,得用synchronized進(jìn)行加鎖保護(hù)
3>如果異步操作要保證線程安全等問(wèn)題,盡量使用GCD(有些函數(shù)默認(rèn)就是安全的)
6.GCD內(nèi)部怎么實(shí)現(xiàn)的
1> iOS和OS X的核心是XNU內(nèi)核第美,GCD是基于XNU內(nèi)核實(shí)現(xiàn)的
2> GCD的API全部在libdispatch庫(kù)中
3> GCD的底層實(shí)現(xiàn)主要有Dispatch Queue和Dispatch Source
Dispatch Queue:管理block(操作)
Dispatch Source:處理事件
7.你用過(guò)NSOperationQueue么?如果用過(guò)或者了解的話陆爽,你為什么要使用NSOperationQueue什往,實(shí)現(xiàn)了什么?請(qǐng)描述它和GCD的區(qū)別和類似的地方(提示:可以從兩者的實(shí)現(xiàn)機(jī)制和適用范圍來(lái)描述)慌闭。
1> GCD是純C語(yǔ)言的API别威,NSOperationQueue是基于GCD的OC版本封裝
2> GCD只支持FIFO的隊(duì)列,NSOperationQueue可以很方便地調(diào)整執(zhí)行順序驴剔、設(shè)置最大并發(fā)數(shù)量
3> NSOperationQueue可以在輕松在Operation間設(shè)置依賴關(guān)系省古,而GCD需要寫很多的代碼才能實(shí)現(xiàn)
4> NSOperationQueue支持KVO,可以監(jiān)測(cè)operation是否正在執(zhí)行(isExecuted)丧失、是否結(jié)束(isFinished)豺妓,是否取消(isCanceld)
5> GCD的執(zhí)行速度比NSOperationQueue快
任務(wù)之間不太互相依賴:GCD
任務(wù)之間有依賴\或者要監(jiān)聽(tīng)任務(wù)的執(zhí)行情況:NSOperationQueue
8.既然提到GCD,那么問(wèn)一下在使用GCD以及block時(shí)要注意些什么布讹?它們兩是一回事兒么琳拭?block在ARC中和傳統(tǒng)的MRC中的行為和用法有沒(méi)有什么區(qū)別,需要注意些什么描验?
Block的使用注意:
block的內(nèi)存管理
防止循環(huán)retian
非ARC(MRC):__block
ARC:__weak\__unsafe_unretained
9.在異步線程中下載很多圖片,如果失敗了,該如何處理?請(qǐng)結(jié)合RunLoop來(lái)談?wù)劷鉀Q方案.(提示:在異步線程中啟動(dòng)一個(gè)RunLoop重新發(fā)送網(wǎng)絡(luò)請(qǐng)求,下載圖片)
1>重新下載圖片
2>下載完畢,利用RunLoop的輸入源回到主線程刷新UIImageVIUew
10. Socket的實(shí)現(xiàn)原理及Socket之間是如何通信的
11.http協(xié)議的實(shí)現(xiàn)
GCD怎么用的白嘁?
?1.串行隊(duì)列,同步操作膘流,不會(huì)新建線程絮缅,操作順序執(zhí)行;
?串行隊(duì)列睡扬,異步操作盟蚣,會(huì)新建線程,操作順序進(jìn)行卖怜,使用場(chǎng)景:既不影響主線程屎开,又需要順序執(zhí)行的操作;
?2.并行隊(duì)列马靠,同步操作奄抽,不會(huì)新建縣城,操作順序執(zhí)行甩鳄;
?并行隊(duì)列逞度,異步操作,會(huì)新建線程妙啃,操作無(wú)序進(jìn)行档泽,隊(duì)列前如果有其他任務(wù)俊戳,會(huì)等待其他任務(wù)執(zhí)行完畢再執(zhí)行;
?全局隊(duì)列是系統(tǒng)的馆匿,直接get就可以用
?UI的更新工作必須在主線程進(jìn)行抑胎,
?全局隊(duì)列異步操作,會(huì)新建對(duì)個(gè)子線程渐北,操作無(wú)序執(zhí)行阿逃,如果隊(duì)列前有其他任務(wù),會(huì)等待其他任務(wù)執(zhí)行完畢在調(diào)用赃蛛;
?全局隊(duì)列同步操作恃锉,不會(huì)新建線程,順序執(zhí)行
?主隊(duì)列所有的操作都是主線程順序執(zhí)行呕臂,沒(méi)有異步概念破托,主隊(duì)列添加的同步操作永遠(yuǎn)不會(huì)執(zhí)行,會(huì)死鎖
?單例模式
?allocwithzone是對(duì)象分配內(nèi)存空間時(shí)诵闭,最終會(huì)調(diào)用的方法炼团,重寫該方法,保證只會(huì)分配一塊內(nèi)存dispatch_once是線程安全的疏尿,保證塊代碼中的內(nèi)容只會(huì)執(zhí)行一次
?
?串行隊(duì)列添加的同步操作會(huì)死鎖瘟芝,但是會(huì)執(zhí)行嵌套同步操作之前的代碼;
?并行隊(duì)列添加的同步操作不會(huì)死鎖都在主線程執(zhí)行褥琐;
?全局隊(duì)列添加的同步操作不會(huì)死鎖锌俱。
?
?同步操作最主要的目的,阻塞并行隊(duì)列任務(wù)的執(zhí)行敌呈,只有當(dāng)前的同步任務(wù)執(zhí)行完畢之后贸宏,后邊的任務(wù)才會(huì)執(zhí)行,應(yīng)用:用戶登錄
?>1隊(duì)列和線程的區(qū)別:
隊(duì)列:是管理線程的磕洪,相當(dāng)于線程池,能管理線程什么時(shí)候執(zhí)行吭练。
隊(duì)列分為串行隊(duì)列和并行隊(duì)列
串行隊(duì)列:隊(duì)列中的線程按順序執(zhí)行(不會(huì)同時(shí)執(zhí)行)
并行隊(duì)列:隊(duì)列中的線程會(huì)并發(fā)執(zhí)行,可能會(huì)有一個(gè)疑問(wèn)析显,隊(duì)列不是先進(jìn)先出嗎鲫咽,如果后面的任務(wù)執(zhí)行完了,怎么出去的了谷异。這里需要強(qiáng)調(diào)下分尸,任務(wù)執(zhí)行完畢了,不一定出隊(duì)列歹嘹。只有前面的任務(wù)執(zhí)行完了箩绍,才會(huì)出隊(duì)列,也就是說(shuō)你即使執(zhí)行完畢了尺上,也必須等前面的任務(wù)執(zhí)行完畢出隊(duì)列材蛛,才可以出去圆到。
?>2主線程隊(duì)列和GCD創(chuàng)建的隊(duì)列也是有區(qū)別的。
主線程隊(duì)列和GCD創(chuàng)建的隊(duì)列是不同的仰税。在GCD中創(chuàng)建的隊(duì)列優(yōu)先級(jí)沒(méi)有主隊(duì)列高构资,所以在GCD中的串行隊(duì)列開(kāi)啟同步任務(wù)里面沒(méi)有嵌套任務(wù)是不會(huì)阻塞主線程,只有一種可能導(dǎo)致死鎖陨簇,就是串行隊(duì)列里,嵌套開(kāi)啟任務(wù)迹淌,有可能會(huì)導(dǎo)致死鎖河绽。
主線程隊(duì)列中不能開(kāi)啟同步,會(huì)阻塞主線程唉窃。只能開(kāi)啟異步任務(wù)耙饰,開(kāi)啟異步任務(wù)也不會(huì)開(kāi)啟新的線程,只是降低異步任務(wù)的優(yōu)先級(jí)纹份,讓cpu空閑的時(shí)候才去調(diào)用苟跪。而同步任務(wù),會(huì)搶占主線程的資源蔓涧,會(huì)造成死鎖件已。
?3>線程:里面有非常多的任務(wù)(同步,異步)
同步與異步的區(qū)別:
同步任務(wù)優(yōu)先級(jí)高元暴,在線程中有執(zhí)行順序篷扩,不會(huì)開(kāi)啟新的線程。
異步任務(wù)優(yōu)先級(jí)低茉盏,在線程中執(zhí)行沒(méi)有順序鉴未,看cpu閑不閑。在主隊(duì)列中不會(huì)開(kāi)啟新的線程鸠姨,其他隊(duì)列會(huì)開(kāi)啟新的線程铜秆。
??*主線程隊(duì)列注意:
下面代碼執(zhí)行順序
1111
2222
主隊(duì)列異步{name = (null), num = 1}
在主隊(duì)列開(kāi)啟異步任務(wù),不會(huì)開(kāi)啟新的線程而是依然在主線程中執(zhí)行代碼塊中的代碼讶迁。為什么不會(huì)阻塞線程连茧?
>主隊(duì)列開(kāi)啟異步任務(wù),雖然不會(huì)開(kāi)啟新的線程添瓷,但是他會(huì)把異步任務(wù)降低優(yōu)先級(jí)梅屉,等閑著的時(shí)候,就會(huì)在主線程上執(zhí)行異步任務(wù)鳞贷。
在主隊(duì)列開(kāi)啟同步任務(wù)坯汤,為什么會(huì)阻塞線程?
>在主隊(duì)列開(kāi)啟同步任務(wù)搀愧,因?yàn)橹麝?duì)列是串行隊(duì)列惰聂,里面的線程是有順序的疆偿,先執(zhí)行完一個(gè)線程才執(zhí)行下一個(gè)線程,而主隊(duì)列始終就只有一個(gè)主線程搓幌,主線程是不會(huì)執(zhí)行完畢的杆故,因?yàn)樗菬o(wú)限循環(huán)的,除非關(guān)閉應(yīng)用程序溉愁。因此在主線程開(kāi)啟一個(gè)同步任務(wù)处铛,同步任務(wù)會(huì)想搶占執(zhí)行的資源,而主線程任務(wù)一直在執(zhí)行某些操作拐揭,不肯放手撤蟆。兩個(gè)的優(yōu)先級(jí)都很高,最終導(dǎo)致死鎖堂污,阻塞線程了家肯。
?- (void)main_queue_deadlock
{
dispatch_queue_t q = dispatch_get_main_queue();
NSLog(@"1111");
dispatch_async(q, ^{
NSLog(@"主隊(duì)列異步%@", [NSThread currentThread]);
});
NSLog(@"2222");
//下面會(huì)造成線程死鎖
//??? dispatch_sync(q, ^{
//??????? NSLog(@"主隊(duì)列同步%@", [NSThread currentThread]);
//??? });
}
?并行隊(duì)列里開(kāi)啟同步任務(wù)是有執(zhí)行順序的,只有異步才沒(méi)有順序盟猖;
?串行隊(duì)列開(kāi)啟異步任務(wù)讨衣,是有順序的
?串行隊(duì)列開(kāi)啟異步任務(wù)后嵌套同步任務(wù)造成死鎖
?- (void)serial_queue_deadlock2
?{
?dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);
?
?
?dispatch_async(q, ^{
?NSLog(@"異步任務(wù)%@", [NSThread currentThread]);
?//下面開(kāi)啟同步造成死鎖:因?yàn)榇嘘?duì)列中線程是有執(zhí)行順序的,需要等上面開(kāi)啟的異步任務(wù)執(zhí)行完畢式镐,才會(huì)執(zhí)行下面開(kāi)啟的同步任務(wù)反镇。而上面的異步任務(wù)還沒(méi)執(zhí)行完,要到下面的大括號(hào)才算執(zhí)行完畢碟案,而下面的同步任務(wù)已經(jīng)在搶占資源了愿险,就會(huì)發(fā)生死鎖。
?dispatch_sync(q, ^{
?NSLog(@"同步任務(wù)%@", [NSThread currentThread]);
?});
?
?});
?串行隊(duì)列開(kāi)啟同步任務(wù)后嵌套同步任務(wù)造成死鎖
?- (void)serial_queue_deadlock1
?{
?dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);
?
?dispatch_sync(q, ^{
?NSLog(@"同步任務(wù)%@", [NSThread currentThread]);
?//下面開(kāi)啟同步造成死鎖:因?yàn)榇嘘?duì)列中線程是有執(zhí)行順序的价说,需要等上面開(kāi)啟的同步任務(wù)執(zhí)行完畢辆亏,才會(huì)執(zhí)行下面開(kāi)啟的同步任務(wù)。而上面的同步任務(wù)還沒(méi)執(zhí)行完鳖目,要到下面的大括號(hào)才算執(zhí)行完畢扮叨,而下面的同步任務(wù)已經(jīng)在搶占資源了,就會(huì)發(fā)生死鎖领迈。
?dispatch_sync(q, ^{
?NSLog(@"同步任務(wù)%@", [NSThread currentThread]);
?});
?
?});
?NSLog(@"同步任務(wù)%@", [NSThread currentThread]);
?}
?串行隊(duì)列開(kāi)啟同步任務(wù)后嵌套異步任務(wù)不造成死鎖
網(wǎng)絡(luò):
PUT方法
// PUT
//??? 1)文件大小無(wú)限制
//??? 2)可以覆蓋文件
// POST
//??? 1)通常有限制2M
//??? 2)新建文件,不能重名
BASE 64是網(wǎng)絡(luò)傳輸中最常用的編碼格式-用來(lái)將二進(jìn)制的數(shù)據(jù)編碼成字符串的編碼方式
BASE 64的用法:
1>能夠編碼,能夠解碼
2>被很多的加密算法作為基礎(chǔ)算法
Session,全局單例(我們能夠給全局的session設(shè)置代理嗎?如果不能為什么?)
// sharedSession是全局共享的,因此如果要設(shè)置代理,需要單獨(dú)實(shí)例化一個(gè)Session
NSURLSessionConfiguration(會(huì)話配置)
defaultSessionConfiguration;?????? //磁盤緩存,適用于大的文件上傳下載
ephemeralSessionConfiguration;???? //內(nèi)存緩存,適用于小的文件交互,GET一個(gè)頭像
backgroundSessionConfiguration:(NSString *)identifier; //后臺(tái)上傳和下載
下載的位置,沙盒中tmp目錄中的臨時(shí)文件,會(huì)被及時(shí)刪除
document備份,下載的文件不能放在此文件夾中
cache緩存的,不備份,重新啟動(dòng)不會(huì)被清空,如果緩存內(nèi)容過(guò)多,可以考慮新建一條線程檢查緩存目錄中的文件大小,自動(dòng)清理緩存,給用戶節(jié)省控件
tmp臨時(shí),不備份,不緩存,重新啟動(dòng)iPhone,會(huì)自動(dòng)清空
直接通過(guò)文件名就可以加載圖像,圖像會(huì)常駐內(nèi)存,具體的銷毀有系統(tǒng)負(fù)責(zé)
// [UIImage imageNamed:@"”];
//從網(wǎng)絡(luò)下載下來(lái)的是二進(jìn)制數(shù)據(jù)
NSData *data = [NSData dataWithContentsOfURL:location];
/這種方式的圖像會(huì)自動(dòng)釋放,不占據(jù)內(nèi)存,也不需要放在臨時(shí)文件夾中緩存
//如果用戶需要,可以提供一個(gè)功能,保存到用戶的相冊(cè)即可
UIImage *image = [UIImage imageWithData:data];
要使用常規(guī)的AFN網(wǎng)絡(luò)訪問(wèn)
1. AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
所有的網(wǎng)絡(luò)請(qǐng)求,均有manager發(fā)起
2.需要注意的是,默認(rèn)提交請(qǐng)求的數(shù)據(jù)是二進(jìn)制的,返回格式是JSON
1>如果提交數(shù)據(jù)是JSON的,需要將請(qǐng)求格式設(shè)置為AFJSONRequestSerializer
2>如果返回格式不是JSON的,
3.請(qǐng)求格式
AFHTTPRequestSerializer二進(jìn)制格式
AFJSONRequestSerializer??????????? JSON
AFPropertyListRequestSerializer??? PList(是一種特殊的XML,解析起來(lái)相對(duì)容易)
4.返回格式
AFHTTPResponseSerializer二進(jìn)制格式
AFJSONResponseSerializer?????????? JSON
AFXMLParserResponseSerializer????? XML,只能返回XMLParser,還需要自己通過(guò)代理方法解析
AFXMLDocumentResponseSerializer (Mac OS X)
AFPropertyListResponseSerializer?? PList
AFImageResponseSerializer????????? Image
AFCompoundResponseSerializer組合
所有網(wǎng)絡(luò)請(qǐng)求,統(tǒng)一使用異步請(qǐng)求!
在今后的開(kāi)發(fā)中,如果使用簡(jiǎn)單的get/head請(qǐng)求,可以用NSURLConnction異步方法
GET查/POST增/PUT改/DELETE刪/HEAD
GET
1> URL
2> NSURLRequest
3> NSURLConnction異步
POST
1> URL
2> NSMutableURLRequest
.httpMethod = @"POST";
str從firebug直接粘貼,或者自己寫
變量名1=數(shù)值1&變量名2=數(shù)值2
.httpData = [str dataUsingEncoding:NSUTF8StringEncoding];
3> NSURLConnction異步
Connection
// 1>登錄完成之前,不能做后續(xù)工作!
// 2>登錄進(jìn)行中,可以允許用戶干點(diǎn)別的會(huì)更好!
// 3>讓登錄操作在其他線程中進(jìn)行,就不會(huì)阻塞主線程的工作
// 4>結(jié)論:登陸也是異步訪問(wèn),中間需要阻塞住
數(shù)據(jù)解析:
從iOS 5開(kāi)始彻磁,使用NSJSONSerialization對(duì)JSON解析
反序列化
[NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
序列化
[NSJSONSerialization dataWithJSONObject:array options:0 error:NULL];
1> PUT方法
// PUT
//1)文件大小無(wú)限制
//2)可以覆蓋文件
// POST
//1)通常有限制2M
//2)新建文件,不能重名
// 2>安全認(rèn)證
// admin:123456
// result base64編碼
// Basic result
/**
BASE 64是網(wǎng)絡(luò)傳輸中最常用的編碼格式-用來(lái)將二進(jìn)制的數(shù)據(jù)編碼成字符串的編碼方式
BASE 64的用法:
1>能夠編碼,能夠解碼
2>被很多的加密算法作為基礎(chǔ)算法
3. Session,全局單例(我們能夠給全局的session設(shè)置代理嗎?如果不能為什么?)
// sharedSession是全局共享的,因此如果要設(shè)置代理,需要單獨(dú)實(shí)例化一個(gè)Session
/**
NSURLSessionConfiguration(會(huì)話配置)
defaultSessionConfiguration;//磁盤緩存,適用于大的文件上傳下載
ephemeralSessionConfiguration;//內(nèi)存緩存,適用于小的文件交互,GET一個(gè)頭像
backgroundSessionConfiguration:(NSString *)identifier; //后臺(tái)上傳和下載
/**
AFNetworkReachabilityStatusUnknown= -1,//未知
AFNetworkReachabilityStatusNotReachable= 0,//無(wú)連接
AFNetworkReachabilityStatusReachableViaWWAN = 1,// 3G花錢
AFNetworkReachabilityStatusReachableViaWiFi = 2,//局域網(wǎng)絡(luò),不花錢
*/
//如果要檢測(cè)網(wǎng)絡(luò)狀態(tài)的變化,必須用檢測(cè)管理器的單例的startMonitoring
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
//檢測(cè)網(wǎng)絡(luò)連接的單例,網(wǎng)絡(luò)變化時(shí)的回調(diào)方法
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(@"%d", status);
}];
音頻處理
依賴的框架:AVFoundation、AudioToolbox框架
播放長(zhǎng)音樂(lè):AVAudioPlayer
播放短音效:加載音頻文件生成SystemSoundID
錄音:AVAudioRecord
較為底層狸捅、高級(jí)的音頻\視頻處理
CoreAudio衷蜓、CoreVideo框架
XMPP工作原理
節(jié)點(diǎn)連接到服務(wù)器
服務(wù)器利用本地目錄系統(tǒng)中的證書對(duì)其認(rèn)證
節(jié)點(diǎn)指定目標(biāo)地址,讓服務(wù)器告知目標(biāo)狀態(tài)
服務(wù)器查找尘喝、連接并進(jìn)行相互認(rèn)證
節(jié)點(diǎn)之間進(jìn)行交互
XMPP框架提供的主要擴(kuò)展功能
XMPPReconnect:如果意外中斷磁浇,自動(dòng)重連XMPP流
XMPPRoster:標(biāo)準(zhǔn)的XMPP花名冊(cè)
XMPPRoom:提供多人聊天支持
XMPPPubSub:提供公共訂閱支持
通信類別及公共XML屬性
使用XMPP的實(shí)時(shí)消息傳遞系統(tǒng)包含三大通信類別:
消息傳遞,其中數(shù)據(jù)在有關(guān)各方之間傳輸
聯(lián)機(jī)狀態(tài)朽褪,允許用戶廣播其在線狀態(tài)和可用性
信息/查詢請(qǐng)求置吓,它允許XMPP實(shí)體發(fā)起請(qǐng)求并從另一個(gè)實(shí)體接收響應(yīng)
以上三種類型的XMPP節(jié)都擁有以下公共屬性:
from:源XMPP實(shí)體的JID
to:目標(biāo)接收者的JID
id:當(dāng)前對(duì)話的可選標(biāo)識(shí)符
type:節(jié)的可選子類型
xml:lang:如果內(nèi)容是人們可讀的无虚,則為消息語(yǔ)言的描述
XMPP核心文件
XMPPStream:是開(kāi)發(fā)過(guò)程中最主要交互的類,所有擴(kuò)展和自定義代碼均要基于此類進(jìn)行
XMPPParser:供XMPPStream解析使用
XMPPJID:提供了一個(gè)不可變JID的實(shí)現(xiàn)衍锚,遵守NSCopying協(xié)議和NSCoding協(xié)議
XMPPElement:以下三個(gè)XMPP元素的基類
XMPPIQ:請(qǐng)求
XMPPMessage:消息
XMPPPresence:出席
XMPPModule:開(kāi)發(fā)XMPP擴(kuò)展時(shí)使用
XMPPLogging:XMPP的日志框架
XMPPInternal:整個(gè)XMPP框架內(nèi)部使用的核心和高級(jí)底層內(nèi)容
XMPP框架常用擴(kuò)展
XEP-0045:多用戶聊天
XEP-0060:發(fā)布-訂閱
XEP-0065: SOCKS5字節(jié)流
XEP-0085:聊天狀態(tài)通知
XEP-0096:文件傳輸
XEP-0172:用戶昵稱
XEP-0184:消息送達(dá)
CoreDataStorage:數(shù)據(jù)存儲(chǔ)
Reconnect:重新連接
Roster:花名冊(cè)
XMPP一欄的框架
CocoaLumberjack:日志框架
CocoaAsyncSocket:底層網(wǎng)絡(luò)框架友题,實(shí)現(xiàn)異步Socket網(wǎng)絡(luò)通訊
需要添加CFNetwork&Security框架依賴
KissXML:XML解析框架
需要添加libxml2.dylib框架依賴
需要指定如下編譯選項(xiàng):
OTHER_LDFLAGS = -lxml2
HEADER_SEARCH_PATHS = /usr/include/libxml2
libidn
網(wǎng)絡(luò)面試:
TCP:安全的協(xié)議,能保證數(shù)據(jù)順序和正確性戴质,服務(wù)器和客戶端能隨時(shí)互發(fā)數(shù)據(jù)度宦。如果服務(wù)器要主動(dòng)發(fā)送數(shù)據(jù)給客戶端,可以用這個(gè)協(xié)議
UDP:非安全的協(xié)議告匠,容易丟失數(shù)據(jù)斗埂,一般用于聯(lián)機(jī)對(duì)戰(zhàn)的游戲
XMPP:基于XML通訊的協(xié)議,基于TCP發(fā)送XML數(shù)據(jù)凫海,一般用于即時(shí)通訊(比如QQ、微信)
HTTP:一般用于非實(shí)時(shí)連接的請(qǐng)求男娄,只有客戶端主動(dòng)向服務(wù)器發(fā)送請(qǐng)求時(shí)行贪,服務(wù)器才能返回?cái)?shù)據(jù)給客戶端
SOCKET:套接口,可以使用TCP/UDP/XMPP通訊
200表示是一個(gè)正確的請(qǐng)求模闲,206表示請(qǐng)求只加載了一部分建瘫,404表示網(wǎng)絡(luò)請(qǐng)求的頁(yè)面不存在;狀態(tài)編碼尸折,503表示服務(wù)器超時(shí)啰脚,400請(qǐng)求出錯(cuò)
斷點(diǎn)續(xù)傳:客戶端軟件斷點(diǎn)續(xù)傳值的時(shí)在下載或者上傳時(shí),將下載或者上傳的文件認(rèn)為的劃分成幾個(gè)部分实夹,每個(gè)部分一個(gè)線程進(jìn)行上傳或者下載的橄浓,如果網(wǎng)絡(luò)異常,可以從上傳或者下載的部分重新上傳或者下載未上傳下載的部分亮航,提高速度荸实,節(jié)省時(shí)間。
創(chuàng)建串行隊(duì)列加入異步任務(wù)
生成文件名,用該文件名和存放路徑生成文件路徑
發(fā)送網(wǎng)絡(luò)請(qǐng)求獲取待生成文件文件大小
設(shè)定每次下載的字節(jié)數(shù),循環(huán)下載(循環(huán)判斷是剩余字節(jié)是否大于循環(huán)下載字節(jié))
發(fā)送請(qǐng)求時(shí)設(shè)定http頭的range范圍,根據(jù)每次循環(huán)fromB和toB來(lái)設(shè)定
每次下載成功返回的數(shù)據(jù)寫入到之前設(shè)定好的文件中
Socket連接與HTTP連接
由于通常情況下Socket連接就是TCP連接缴淋,因此Socket連接一旦建立准给,通信雙方即可開(kāi)始相互發(fā)送數(shù)據(jù)內(nèi)容,直到雙方連接斷開(kāi)重抖。但在實(shí)際網(wǎng)絡(luò)應(yīng)用中露氮,客戶端到服務(wù)器之間的通信往往需要穿越多個(gè)中間節(jié)點(diǎn),例如路由器钟沛、網(wǎng)關(guān)畔规、防火墻等,大部分防火墻默認(rèn)會(huì)關(guān)閉長(zhǎng)時(shí)間處于非活躍狀態(tài)的連接而導(dǎo)致Socket連接斷連讹剔,因此需要通過(guò)輪詢告訴網(wǎng)絡(luò)油讯,該連接處于活躍狀態(tài)详民。
而HTTP連接使用的是“請(qǐng)求—響應(yīng)”的方式,不僅在請(qǐng)求時(shí)需要先建立連接陌兑,而且需要客戶端向服務(wù)器發(fā)出請(qǐng)求后沈跨,服務(wù)器端才能回復(fù)數(shù)據(jù)。
很多情況下兔综,需要服務(wù)器端主動(dòng)向客戶端推送數(shù)據(jù)饿凛,保持客戶端與服務(wù)器數(shù)據(jù)的實(shí)時(shí)與同步。此時(shí)若雙方建立的是Socket連接软驰,服務(wù)器就可以直接將數(shù)據(jù)傳送給客戶端涧窒;若雙方建立的是HTTP連接,則服務(wù)器需要等到客戶端發(fā)送一次請(qǐng)求后才能將數(shù)據(jù)傳回給客戶端锭亏,因此纠吴,客戶端定時(shí)向服務(wù)器端發(fā)送連接請(qǐng)求,不僅可以保持在線慧瘤,同時(shí)也是在“詢問(wèn)”服務(wù)器是否有新的數(shù)據(jù)戴已,如果有就將數(shù)據(jù)傳給客戶端。
http基于socket做出來(lái)的锅减,所有的網(wǎng)絡(luò)功能都是基于socket做出來(lái)的糖儡,比如:即時(shí)通訊,ftp
//收到內(nèi)存警告會(huì)自動(dòng)調(diào)用
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
文件存儲(chǔ):
Plist文件存儲(chǔ)
// 1.獲得沙盒根路徑
NSString *home = NSHomeDirectory();
// 2.document路徑
NSString *docPath = [home stringByAppendingPathComponent:@"Documents"];
// 3.新建數(shù)據(jù)
NSArray *data = @[@"jack", @10, @"ffdsf"];
// 4.將數(shù)據(jù)寫入沙盒document目錄的data.plist文件中
NSString *filepath = [docPath stringByAppendingPathComponent:@"data.plist"];
[data writeToFile:filepath atomically:YES];
// 5.讀取數(shù)據(jù)
NSArray *data = [NSArray arrayWithContentsOfFile:filepath];
NSLog(@"%@", data);
偏好設(shè)置存儲(chǔ)
// 1.利用NSUserDefaults,就能直接訪問(wèn)軟件的偏好設(shè)置(Library/Preferences)
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 2.存儲(chǔ)數(shù)據(jù)
[defaults setObject:@"mj" forKey:@"account"];
[defaults setObject:@"123" forKey:@"pwd"];
[defaults setInteger:10 forKey:@"age"];
[defaults setBool:YES forKey:@"auto_login"];
// 3.立刻同步
[defaults synchronize];
// 4.讀取數(shù)據(jù)
NSString *account = [defaults objectForKey:@"account"];
BOOL autoLogin = [defaults boolForKey:@"auto_login”];
NSKeyedArchiver和NSKeyedUnarchiver
MJStudent實(shí)現(xiàn)協(xié)議的方法
/**
*將某個(gè)對(duì)象寫入文件時(shí)會(huì)調(diào)用
*在這個(gè)方法中說(shuō)清楚哪些屬性需要存儲(chǔ)
*/
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:self.noforKey:@"no"];
[encoder encodeInt:self.age forKey:@"age"];
[encoder encodeDouble:self.height forKey:@"height"];
}
/**
*從文件中解析對(duì)象時(shí)會(huì)調(diào)用
*在這個(gè)方法中說(shuō)清楚哪些屬性需要存儲(chǔ)
*/
- (id)initWithCoder:(NSCoder *)decoder
{
if (self = [super init]) {
//讀取文件的內(nèi)容
self.no= [decoder decodeObjectForKey:@"no"];
self.age = [decoder decodeIntForKey:@"age"];
self.height = [decoder decodeDoubleForKey:@"height"];
}
return self;
}
MJStudent *stu1 = [[MJStudent alloc] init];
stu1.no= @"42343254";
stu1.age = 20;
stu1.height = 1.55;
MJStudent *stu2 = [[MJStudent alloc] init];
stu2.no= @"42343254";
stu2.age = 20;
stu2.height = 1.55;
//新建一塊可變數(shù)據(jù)區(qū)
NSMutableData *data = [NSMutableData data];
//將數(shù)據(jù)區(qū)連接到一個(gè)NSKeyedArchiver對(duì)象
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
//開(kāi)始存檔對(duì)象怔匣,存檔的數(shù)據(jù)都會(huì)存儲(chǔ)到NSMutableData中
[archiver encodeObject:stu1 forKey:@"person1"];
[archiver encodeObject:stu2 forKey:@"person2"];
//存檔完畢(一定要調(diào)用這個(gè)方法)
[archiver finishEncoding];
//將存檔的數(shù)據(jù)寫入文件
[data writeToFile:path atomically:YES]
//從文件中讀取數(shù)據(jù)
NSData *data = [NSData dataWithContentsOfFile:path];
//根據(jù)數(shù)據(jù)握联,解析成一個(gè)NSKeyedUnarchiver對(duì)象
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
MJStudent *stu11 = [unarchiver decodeObjectForKey:@"stu1"];
MJStudent *stu22= [unarchiver decodeObjectForKey:@"stu2"];
//恢復(fù)完畢
[unarchiver finishDecoding];
如果父類也遵守了NSCoding協(xié)議,請(qǐng)注意:應(yīng)該在encodeWithCoder:方法中加上一句
[super encodeWithCode:encode];確保繼承的實(shí)例變量也能被編碼每瞒,即也能被歸檔
應(yīng)該在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];
確保繼承的實(shí)例變量也能被解碼金闽,即也能被恢復(fù)
利用解歸檔實(shí)現(xiàn)深復(fù)制
通過(guò)解歸檔,被歸檔的對(duì)象,再被解檔后,內(nèi)存地址已經(jīng)不一樣了,即實(shí)現(xiàn)了深復(fù)制
數(shù)據(jù)庫(kù)的線程安全:
如果是coredata垂睬,需要將context放在主線程上治力;因?yàn)閏ontext統(tǒng)一負(fù)責(zé)數(shù)據(jù)庫(kù)的讀寫操作
1.全局隊(duì)列與并行隊(duì)列的區(qū)別
dispatch_queue_t q =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1>不需要?jiǎng)?chuàng)建,直接GET就能用
2>兩個(gè)隊(duì)列的執(zhí)行效果相同
3>全局隊(duì)列沒(méi)有名稱嘲叔,調(diào)試時(shí)懦砂,無(wú)法確認(rèn)準(zhǔn)確隊(duì)列
4>全局隊(duì)列有高中默認(rèn)優(yōu)先級(jí)
2.并行隊(duì)列
dispatch_queue_t q =
dispatch_queue_create("ftxbird", DISPATCH_QUEUE_CONCURRENT);
3.串行隊(duì)列
dispatch_queue_t t = dispatch_queue_create("ftxbird",DISPATCH_QUEUE_SERIAL);
4.開(kāi)發(fā)中蜒犯,跟蹤當(dāng)前線程
[NSThread currentThread]
5.并行隊(duì)列的任務(wù)嵌套例子
dispatch_queue_t q = dispatch_queue_create("ftxbird", DISPATCH_QUEUE_CONCURRENT);
//任務(wù)嵌套
dispatch_sync(q, ^{
NSLog(@"1 %@", [NSThread currentThread]);
dispatch_sync(q, ^{
NSLog(@"2 %@", [NSThread currentThread]);
dispatch_sync(q, ^{
NSLog(@"3 %@", [NSThread currentThread]);
});
});
dispatch_async(q, ^{
NSLog(@"4 %@", [NSThread currentThread]);
});
NSLog(@"5 %@", [NSThread currentThread]);
});
//運(yùn)行結(jié)果是: 12345或12354
6.主隊(duì)列(線程)
1>每一個(gè)應(yīng)用程序都只有一個(gè)主線程
2>所有UI的更新工作,都必須在主線程上執(zhí)行荞膘!
3>主線程是一直工作的罚随,而且除非將程序殺掉,否則主線程的工作永遠(yuǎn)不會(huì)結(jié)束羽资!
dispatch_queue_t q = dispatch_get_main_queue();
7.在主隊(duì)列上更新UI的例子
//創(chuàng)建代碼塊
void (^TaskOne)(void) = ^(void)
{
NSLog(@"Current thread = %@", [NSThread currentThread]);
NSLog(@"Main thread = %@", [NSThread mainThread]);
[[[UIAlertView alloc] initWithTitle:@"GCD"
message:@"Great Center Dispatcher"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];
};
//取得分發(fā)隊(duì)列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//提交任務(wù)
dispatch_async(mainQueue, TaskOne);
}
//簡(jiǎn)便寫法
dispatch_async( dispatch_get_main_queue(), ^(void)
{
NSLog(@"Current thread = %@", [NSThread currentThread]);
NSLog(@"Main thread = %@", [NSThread mainThread]);
[[[UIAlertView alloc] initWithTitle:@"GCD"
message:@"Great Center Dispatcher"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];
});
//輸出結(jié)果
//2014-05-02 20:34:27.872 serirl[835:60b] Current thread = {name = (null), num = 1}
//2014-05-02 20:34:27.873 serirl[835:60b] Main thread = {name = (null), num = 1}
NSOperation多線程技術(shù)
8.?NSBlockOperation簡(jiǎn)單使用
//開(kāi)發(fā)中一般給自定義隊(duì)列定義為屬性
@property (nonatomic, strong) NSOperationQueue *myQueue;
self.myQueue = [[NSOperationQueue alloc] init];
1>在自定義隊(duì)列
NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
所有的自定義隊(duì)列淘菩,都是在子線程中運(yùn)行.
[self.myQueue addOperation:block];
或者:
[self.myQueue addOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
2>在主隊(duì)列中執(zhí)行
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
3>?NSBlockOperation的使用例子
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下載圖片%@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"修飾圖片%@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"保存圖片%@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"更新UI %@", [NSThread currentThread]);
}];
//設(shè)定執(zhí)行順序, Dependency依賴,可能會(huì)開(kāi)多個(gè),但不會(huì)太多
//依賴關(guān)系是可以跨隊(duì)列的潮改!
[op2 addDependency:op1];
[op3 addDependency:op2];
[op4 addDependency:op3];
// GCD是串行隊(duì)列狭郑,異步任務(wù),只會(huì)開(kāi)一個(gè)線程
[self.myQueue addOperation:op1];
[self.myQueue addOperation:op2];
[self.myQueue addOperation:op3];
//所有UI的更新需要在主線程上進(jìn)行
[[NSOperationQueue mainQueue] addOperation:op4];
9. NSInvocationOperation簡(jiǎn)單使用
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demoOp:) object:@"hello op"];
- (void)demoOp:(id)obj
{
NSLog(@"%@ - %@", [NSThread?currentThread], obj);
}
10.?performSelectorOnMainThread方法使用
// 1>模擬下載汇在,延時(shí)
[NSThread sleepForTimeInterval:1.0];
// 2>設(shè)置圖像翰萨,蘋果底層允許使用performSelectorInBackground方法
//在后臺(tái)線程更新UI,強(qiáng)烈不建議大家這么做糕殉!
// YES會(huì)阻塞住線程亩鬼,直到調(diào)用方法完成
// NO不會(huì)阻塞線程,會(huì)繼續(xù)執(zhí)行
[self performSelectorOnMainThread:@selector(setImage:) withObject:[UIImage imageNamed:imagePath] waitUntilDone:NO];
// 1.圖像
- (void)setImage:(UIImage *)image
{
self.imageView.image = image;
[self.imageView sizeToFit];
}
11.
提問(wèn):代碼存在什么問(wèn)題阿蝶?如果循環(huán)次數(shù)非常大雳锋,會(huì)出現(xiàn)什么問(wèn)題?應(yīng)該如何修改羡洁?
//解決辦法1:如果i比較大玷过,可以在for循環(huán)之后@autoreleasepool
//解決方法2:如果i玩命大,一次循環(huán)都會(huì)造成
自動(dòng)釋放池被填滿,一次循環(huán)就@autoreleasepool
for (int i = 0; i < 10000000; ++i) {
@autoreleasepool {
// *
NSString *str = @"Hello World!";
// new *
str = [str uppercaseString];
// new *
str = [NSString stringWithFormat:@"%@ %d", str, i];
NSLog(@"%@", str);
}
}