在簡(jiǎn)書看到大牛的知識(shí)點(diǎn),發(fā)現(xiàn)很多知識(shí)點(diǎn)自己一知半解,能做項(xiàng)目但理論不夠扎實(shí),默默地去百度總結(jié)一下.放到這里和大家交流交流.
如有侵權(quán),告知即刪!
01.用StoryBoard開(kāi)發(fā)界面有什么弊端?如何避免校焦?
優(yōu)點(diǎn):
開(kāi)發(fā)界面所見(jiàn)即所得竟坛,可以快速通過(guò)拖拽構(gòu)造界面鸭限。
你可以從 storyboard 中很方便地梳理出所有View Controller的界面間的調(diào)用關(guān)系党饮。這一點(diǎn)對(duì)于新加入項(xiàng)目組的開(kāi)發(fā)同事來(lái)說(shuō)悠抹,比較友好夭织。
缺點(diǎn):
xib 對(duì)版本管理是災(zāi)難网杆。storyboard 實(shí)際上的多個(gè) xib 的集合,所以更容易讓多人編輯產(chǎn)生沖突也颤。而雖然它們是 xml 格式旷档,但是沖突解決起來(lái)還是不如代碼那么容易。
蘋果對(duì) xib, storyboard 的設(shè)計(jì)中帶有當(dāng)前電腦的操作系統(tǒng)版本和 Xcode 版本歇拆。所以如果兩個(gè)協(xié)作的開(kāi)發(fā)者電腦操作系統(tǒng)或 Xcode 有不一樣的話,每次打開(kāi)必定會(huì)修改這個(gè)文件范咨。另外即使操作系統(tǒng)版本和 Xcode 版本一樣故觅,有些時(shí)候打開(kāi)看也會(huì)造成一些自動(dòng)的修改。
xib 和 storyboard 不太方便做界面的模塊化管理渠啊,比如我們想統(tǒng)一修改界面中所有按鈕的字體樣式输吏,那么在 xib 和 storyboard 只能一個(gè)一個(gè)手工修改,而如果是代碼編寫的替蛉,則只需要改一個(gè)工廠方法的實(shí)現(xiàn)即可贯溅。
對(duì)于復(fù)雜的 App拄氯,storyboard 的性能會(huì)比較差。
02.進(jìn)程和線程的區(qū)別它浅?同步異步的區(qū)別译柏?并行和并發(fā)的區(qū)別?
先簡(jiǎn)單說(shuō)說(shuō)線程與進(jìn)程的概念:
(1)進(jìn)程是指一個(gè)內(nèi)存中運(yùn)行的應(yīng)用程序姐霍,比如在Windows系統(tǒng)中鄙麦,一個(gè)運(yùn)行的exe就是一個(gè)進(jìn)程。
(2)線程是指進(jìn)程中的一個(gè)執(zhí)行流程镊折。
區(qū)別:
一個(gè)程序至少有一個(gè)進(jìn)程胯府,而一個(gè)進(jìn)程至少有一個(gè)線程。一個(gè)應(yīng)用程序可以同時(shí)啟動(dòng)多個(gè)進(jìn)程恨胚。例如對(duì)于IE瀏覽器程序骂因,每打開(kāi)一個(gè)IE瀏覽器窗口,就啟動(dòng)了一個(gè)新的進(jìn)程赃泡。而線程則是指進(jìn)程中的一個(gè)執(zhí)行流程寒波,一個(gè)進(jìn)程可以有多個(gè)線程,每個(gè)線程分別執(zhí)行不同的任務(wù)急迂,當(dāng)進(jìn)程內(nèi)的多個(gè)線程同時(shí)運(yùn)行時(shí)影所,這種運(yùn)行方式就被稱為并發(fā)運(yùn)行。
另外僚碎,線程與進(jìn)程還有一個(gè)非常重要的區(qū)別:每個(gè)進(jìn)程在執(zhí)行過(guò)程中都擁有獨(dú)立的內(nèi)存單元猴娩,而同一個(gè)進(jìn)程中的多個(gè)線程則共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率勺阐。
1.并發(fā):在操作系統(tǒng)中卷中,是指一個(gè)時(shí)間段中有幾個(gè)程序都處于已啟動(dòng)運(yùn)行到運(yùn)行完畢之間,且這幾個(gè)程序都是在同一個(gè)處理機(jī)上運(yùn)行渊抽。其中兩種并發(fā)關(guān)系分別是同步和互斥
2.互斥:進(jìn)程間相互排斥的使用臨界資源的現(xiàn)象蟆豫,就叫互斥。
3.同步:進(jìn)程之間的關(guān)系不是相互排斥臨界資源的關(guān)系懒闷,而是相互依賴的關(guān)系十减。進(jìn)一步的說(shuō)明:就是前一個(gè)進(jìn)程的輸出作為后一個(gè)進(jìn)程的輸入,當(dāng)?shù)谝粋€(gè)進(jìn)程沒(méi)有輸出時(shí)第二個(gè)進(jìn)程必須等待愤估。具有同步關(guān)系的一組并發(fā)進(jìn)程相互發(fā)送的信息稱為消息或事件帮辟。
其中并發(fā)又有偽并發(fā)和真并發(fā),偽并發(fā)是指單核處理器的并發(fā)玩焰,真并發(fā)是指多核處理器的并發(fā)由驹。
4.并行:在單處理器中多道程序設(shè)計(jì)系統(tǒng)中,進(jìn)程被交替執(zhí)行昔园,表現(xiàn)出一種并發(fā)的外部特種蔓榄;在多處理器系統(tǒng)中并炮,進(jìn)程不僅可以交替執(zhí)行,而且可以重疊執(zhí)行甥郑。在多處理器上的程序才可實(shí)現(xiàn)并行處理逃魄。從而可知,并行是針對(duì)多處理器而言的壹若。并行是同時(shí)發(fā)生的多個(gè)并發(fā)事件嗅钻,具有并發(fā)的含義,但并發(fā)不一定并行店展,也亦是說(shuō)并發(fā)事件之間不一定要同一時(shí)刻發(fā)生养篓。
5.多線程:多線程是程序設(shè)計(jì)的邏輯層概念,它是進(jìn)程中并發(fā)運(yùn)行的一段代碼赂蕴。多線程可以實(shí)現(xiàn)線程間的切換執(zhí)行柳弄。
6.異步:異步和同步是相對(duì)的,同步就是順序執(zhí)行概说,執(zhí)行完一個(gè)再執(zhí)行下一個(gè)碧注,需要等待、協(xié)調(diào)運(yùn)行糖赔。異步就是彼此獨(dú)立,在等待某事件的過(guò)程中繼續(xù)做自己的事萍丐,不需要等待這一事件完成后再工作。線程就是實(shí)現(xiàn)異步的一個(gè)方式放典。異步是讓調(diào)用方法的主線程不需要同步等待另一線程的完成逝变,從而可以讓主線程干其它的事情。
異步和多線程并不是一個(gè)同等關(guān)系,異步是最終目的,多線程只是我們實(shí)現(xiàn)異步的一種手段奋构。異步是當(dāng)一個(gè)調(diào)用請(qǐng)求發(fā)送給被調(diào)用者,而調(diào)用者不用等待其結(jié)果的返回而可以做其它的事情壳影。實(shí)現(xiàn)異步可以采用多線程技術(shù)或則交給另外的進(jìn)程來(lái)處理。
03.線程間通信弥臼?
線程間通信常用的方法
-
NSThread
可以先將自己的當(dāng)前線程對(duì)象注冊(cè)到某個(gè)全局的對(duì)象中去宴咧,這樣相互之間就可以獲取對(duì)方的線程對(duì)象,然后就可以使用下面的方法進(jìn)行線程間的通信了径缅,由于主線程比較特殊掺栅,所以框架直接提供了在主線程執(zhí)行的方法
-(void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
-(void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5,2_0);
用法如下://點(diǎn)擊屏幕開(kāi)始執(zhí)行下載方法
- (void)touchesBegan:(NSSet*)touches withEvent: (UIEvent*)event {
[self performSelectorInBackground:@selector(download) withObject: nil];
}
//下載圖片
- (void)download{
// 1.圖片地址NSString*urlStr =@"http://d.jpg";
NSURL*url = [NSURL URLWithString: urlStr];
// 2.根據(jù)地址下載圖片的二進(jìn)制數(shù)據(jù)
NSData*data = [NSData dataWithContentsOfURL: url];
NSLog(@"---end");
// 3.設(shè)置圖片
UIImage*image = [UIImage imageWithData: data];/
/ 4.回到主線程,刷新UI界面(為了線程安全)
[self performSelectorOnMainThread: @selector(downloadFinished:) withObject: image waitUntilDone:NO];
// [self performSelector:@selector(downloadFinished:) onThread:[NSThread mainThread] withObject: image waitUntilDone:YES];
}
- (void)downloadFinished:(UIImage*)image{
self.imageView.image = image;NSLog(@"downloadFinished---%@", [NSThread currentThread]);
}
GCD一個(gè)線程傳遞數(shù)據(jù)給另一個(gè)線程纳猪,如:
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSLog(@"donwload---%@", [NSThread currentThread]);
// 1.子線程下載圖片
NSURL*url = [NSURLURLWithString:@"http://d.jpg"];
NSData*data = [NSData dataWithContentsOfURL: url];
UIImage*image = [UIImage imageWithData: data];
// 2.回到主線程設(shè)置圖片
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"setting---%@ %@", [NSThread currentThread], image);
[self.button setImage: image forState:UIControlStateNormal];
});
});
}
04.GCD的一些常用的函數(shù)柿冲?(group,barrier兆旬,信號(hào)量,線程同步)
GCD中實(shí)現(xiàn)線程同步的方式
dispatch_group
dispatch_group是GCD中經(jīng)常使用的線程同步方式,具體用法如下:
dispatch_queue_t queue = dispatch_queue_create("cc.imguiqing", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();dispatch_group_async(group, queue, ^{ NSLog(@"task 1 on %@",[NSThread currentThread]);});
dispatch_group_async(group, queue, ^{ NSLog(@"task 2 on %@",[NSThread currentThread]);});
dispatch_group_async(group, queue, ^{ NSLog(@"task 3 on %@",[NSThread currentThread]);
});
可以看出,這個(gè)和普通的GCD任務(wù)相比,每個(gè)API都多了一個(gè)group參數(shù).但是如果僅僅是像上面的方式使用,就沒(méi)有什么必要了.我們使用Group的原因,更多是想要知道這個(gè)Group中的執(zhí)行情況.借此來(lái)獲得時(shí)機(jī)做一些邏輯操作.所以dispatch_group提供了兩個(gè)API:
通知Group中的任務(wù)都執(zhí)行完畢
dispatch_group_notify(group, queue, ^{ NSLog(@"all task done");});
阻塞式的等待Group中的任務(wù)都執(zhí)行完畢
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);NSLog(@"since all done , I move on");
更常見(jiàn)的寫法
上面的寫法雖然簡(jiǎn)單,但是如果看過(guò)一些三方庫(kù)的代碼,發(fā)現(xiàn)那么用的并不多.更多的是利用dispatch_group_enter(group)和dispatch_group_leave(group)來(lái)包裝任務(wù),本質(zhì)上兩者沒(méi)有區(qū)別,多說(shuō)這些僅僅是讓你別以后看代碼的時(shí)候感到疑惑,
代碼如下:
dispatch_queue_t queue = dispatch_get_global_queue(0,0);
dispatch_group_t group = dispatch_group_create();dispatch_group_enter(group);dispatch_async(queue, ^{
NSLog( @"task 1 --- %@", [NSThread currentThread] );
dispatch_group_leave(group);} );
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog( @"task 2 --- %@", [NSThread currentThread] );dispatch_group_leave(group);} );
dispatch_group_notify(group, queue, ^{
NSLog( @"all task done %@", [NSThread currentThread] );
} );
信號(hào)量
信號(hào)量可以理解為一個(gè)特殊的變量.程序?qū)λ脑L問(wèn)都是原子性的,我們通過(guò)PV操作來(lái)修改信號(hào)量.
使用代碼簡(jiǎn)單說(shuō)明:
dispatch_semaphore_t sem =dispatch_semaphore_create(0);
[networkManager requestWithDelay:5completion:^{dispatch_semaphore_signal(sem);//+1}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
//-1NSLog(@"five sectonds");
信號(hào)量創(chuàng)建的時(shí)候, 可以給他指定一個(gè)值.dispatch_semaphore_signal(sem)對(duì)信號(hào)進(jìn)行+1操作.dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER)對(duì)信號(hào)進(jìn)行-1操作.當(dāng)進(jìn)行-1時(shí),如果發(fā)現(xiàn)信號(hào)結(jié)果會(huì)小于0,那么線程進(jìn)入阻塞狀態(tài).只有當(dāng)信號(hào)>=0才能通過(guò).
那么上面的代碼段就容易明白了: 一直等到一個(gè)異步的網(wǎng)絡(luò)請(qǐng)求結(jié)束,才繼續(xù)執(zhí)行NSLog(@"five sectonds");,也是就其他的邏輯
Barrier
相比上面兩種方式,Barrier知道的人相對(duì)少一些.但是Barrier用起來(lái)相對(duì)上面兩種更加簡(jiǎn)單.
dispatch_queue_t queue = dispatch_queue_create("cc.imguiqing", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue,^{
NSLog(@"task 1 on %@",[NSThread currentThread]);});
dispatch_async(queue,^{
NSLog(@"task 2 on %@",[NSThread currentThread]);});
dispatch_barrier_async(queue,^{
NSLog(@"barrier ==========");});
dispatch_async(queue,^{
NSLog(@"task 3 on %@",[NSThread currentThread]);
});
上面的代碼,task 1和task 2會(huì)并發(fā)執(zhí)行,然后執(zhí)行barrier,最后是task 3,用圖來(lái)說(shuō)明:
[圖片上傳中怎栽。丽猬。宿饱。(1)]
這個(gè) barrier就相當(dāng)于一個(gè)柵欄,將不同的任務(wù)區(qū)分開(kāi)來(lái).從代碼中也不難看出,這個(gè)barrier函數(shù)不需要依賴其它的變量,沒(méi)有侵入性.所以非常好用.和Group也是非常好搭配.例如下面的代碼:
dispatch_queue_t queue = dispatch_queue_create("cc.imguiqing", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group =dispatch_group_create();
dispatch_group_async(group, queue, ^{
for (int i =0; i < 500000000; i++) {}
NSLog(@"task 1 on %@",[NSThread currentThread]);});
dispatch_barrier_async(queue,^{
NSLog(@"======");});
dispatch_group_async(group, queue, ^{
for (int i =0; i < 500000000; i++) {}
NSLog(@"task 2 on %@",[NSThread currentThread]);});
dispatch_barrier_async(queue,^{
NSLog(@"======");});
dispatch_group_async(group, queue, ^{
NSLog(@"task 3 on %@",[NSThread currentThread]);});
dispatch_group_notify(group, queue, ^{
NSLog(@"all task done");});
dispatch_group_wait(group,DISPATCH_TIME_FOREVER);
NSLog(@"since all done , I move on");
能保證task 1 2 3順序執(zhí)行,同時(shí),由于使用了Group,也能知道執(zhí)行結(jié)束的時(shí)機(jī). 但是僅僅是為了說(shuō)明問(wèn)題,如果要順序執(zhí)行,那么還是使用GCD中同步隊(duì)列更加合適.
注意點(diǎn): 這個(gè)barrier函數(shù)只能用于并發(fā)隊(duì)列,且不能是global queue.