GCD -Grand Central Dispatch
GCD包含于libdispatch.dylib萨蚕,系統(tǒng)默認加載這個庫
GCD 是純C語言的,函數(shù)大多以dispatch開頭角钩。
任務(wù)和隊列
任務(wù)
既是要執(zhí)行什么任務(wù)诈乒。
隊列
既是存放任務(wù)的。
定制任務(wù)
確定想做的事情
將任務(wù)添加到隊列中烹卒,GCD會自動將隊列中的任務(wù)取出章咧,放到對應(yīng)的線程中執(zhí)行
提示:任務(wù)的取出遵循隊列的FIFO原則:先進先出倦西,后進后出
執(zhí)行任務(wù)
GCD中有2個用來執(zhí)行任務(wù)的函數(shù):
同步方式:dispatch_sync(dispatch_quene_t queue,dispatch_block_t block)
異步方式:dispatch_async(dispatch_queue_t queue,dispatch_block_t block)
把block中的任務(wù)提交給queue隊列來執(zhí)行
同步(dispatch_sync
)和異步(dispatch_async
)的區(qū)別
同步:在當前線程中執(zhí)行
異步:在另一條線程中執(zhí)行
隊列
隊列的類型
GCD的隊列可以分為2大類型:并發(fā)隊列(
Concurrent Dispatch Queue
)和串行隊列(Serial Dispatch Queue
)并發(fā)隊列(Concurrent Dispatch Queue)
可以讓多個任務(wù)并發(fā)(同時)執(zhí)行(自動開啟多個線程同時執(zhí)行任務(wù)),并發(fā)功能只有在異步函數(shù)(
dispatch_async(dispatch_queue_t queue_t,dispatch_block_t block)
)中才有效赁严。串行隊列(Serial Dispatch Queue)
讓任務(wù)一個接著一個執(zhí)行(一個任務(wù)執(zhí)行完畢后扰柠,再執(zhí)行下一個任務(wù))
Tips:容易混淆的幾個概念-同步、異步误澳、并發(fā)耻矮、串行
同步和異步?jīng)Q定要不要開啟新的線程
同步:在當前線程中執(zhí)行任務(wù)秦躯,不具備開啟新線程的能力
異步:在新的線程中執(zhí)行任務(wù)忆谓,具備開啟新線程的能力
并發(fā)和串行決定了任務(wù)的執(zhí)行方式
并發(fā):多個任務(wù)并發(fā)(同時)執(zhí)行
串行:一個任務(wù)執(zhí)行完畢后,再執(zhí)行下一個任務(wù)
串行隊列
使用
dispatch_queue_create
函數(shù)創(chuàng)建串行隊列
函數(shù)原型:
dispatch_queue_t dispatch_queue_create(const char *label,dispatch_queue_attr_t attr)
label
:隊列名稱-C語言的字符串踱承、attr
:隊列屬性-一般用NULL即可示例:
dispatch_queue_t queue = dispatch_queue_create("com.jiakaotuan.Gcd",NULL);
dispatch_release(queue);
//非ARC模式下手動釋放創(chuàng)建的隊列
并發(fā)隊列
GCD默認已經(jīng)提供了全局的并發(fā)隊列倡缠,供整個應(yīng)用使用,不需要手動創(chuàng)建
使用
dispatch_get_global_queue
函數(shù)獲得全局的并發(fā)隊列函數(shù)原型:
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags)
priority
:隊列優(yōu)先級茎活,flags
:保留的參數(shù)-傳0即可昙沦。
priority
代表全局隊列的優(yōu)先級,有以下幾個選項
全局并發(fā)隊列的優(yōu)先級
- #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 // 后臺
- 各種隊列的執(zhí)行效果
全局并發(fā)隊列 | 手動創(chuàng)建串行隊列 | 主隊列 | |
---|---|---|---|
同步(sync) | 沒有開啟新線程,串行執(zhí)行隊列 | 沒有開啟新線程载荔,串行執(zhí)行任務(wù) | 沒有開啟新線程盾饮,串行執(zhí)行任務(wù) |
異步(async) | 有開啟新線程,并發(fā)執(zhí)行任務(wù) | 有開啟新線程串行執(zhí)行任務(wù) | 沒有開啟新線程懒熙,串行執(zhí)行任務(wù) |
GCD
1.dispatch_async
1.為了避免界面在處理耗時的操作時卡死丘损,比如讀取網(wǎng)絡(luò)數(shù)據(jù),IO工扎,數(shù)據(jù)庫讀寫等徘钥,我們會在另外一個線程中處理這些耗時的操作,處理完成之后在主線程更新UI界面肢娘。(記住UI的更新只能在主線程哦)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)),^{ NSURL *url = [NSURL URLWithString:@"http://c.hiphotos.baidu.com/image/h%3D200/sign=a7b8619c4e540923b569647ea259d1dc/50da81cb39dbb6fd786f7a990e24ab18972b375c.jpg"]; NSData *data = [[NSData alloc]initWithContentsOfURL:url]; UIImage *image = [[UIImage alloc]initWithData:data]; if(data != nil && image != nil){ dispatch_async(dispatch_get_main_queue(),^{ self.imageView.image = image; } } }
2.獲取global_queue(并行隊列)
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
3.獲取main_queue(串行隊列)
dispatch_queue_t mainQueue = dispatch_get_main_queue();
2.dispatch_group_async
dispatch_group_async
可以監(jiān)聽一組任務(wù)是否完成呈础,完成后得到通知執(zhí)行其他的操作。比如你進行了2個下載任務(wù)橱健,當這2個下載任務(wù)都完成后你通知界面刷新UI而钞。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group,queue,^{ [NSThread sleepForTimeInterval:1]; NSLog(@"one"); } dispatch_group_async(group,queue,^{ [NSThread sleepForTimeInterval:2]; NSLog(@"two"); } dispatch_group_notify(group,dispatch_get_main_queue(),^{ NSLog(@"updateUI"); } dispatch_release(group);
diapatch_group_async
是異步的方法,運行結(jié)果如下
one
two
updateUI
可以看到在打印完one
和two
之后再打印的updateUI
3.dispatch_barrier_async
dispatch_barrier_async
是在前面的任務(wù)執(zhí)行完畢之后才開始執(zhí)行的,同理要等它執(zhí)行完畢之后拘荡,它后面的任務(wù)才會開始執(zhí)行臼节。
dispatch_queue_t queue = dispatch_queue_create("gcdDemo",DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue,^{ [NSThread sleepForTimeInterval:2]; NSLog(@"dispatch_async_after_2s"); }) dispatch_async(queue,^{ [NSThread sleepForTimeInterval:4]; NSLog(@"dispatch_async_after_4s"); }) dispatch_barrier_async(queue,^{ NSLog(@"dispatch_barrier_async"); [NSThread sleepForTimeInterval:4]; }) dispatch_async(queue,^{ [NSThread sleepForTimeInterval:1]; NSLog(@"dispatch_async_after_1s"); })
注意看打印的時間:
打印時間 | 打印內(nèi)容 | 說明 |
---|---|---|
16:20:33.900 |
dispatch_async_after_2s |
在33s的時候打印的 |
16:20:35.900 |
dispatch_async_after_4s |
在35s的時候打印的,和上一個打印相差2s=(4s-2s) |
16:20:35.900 |
dispatch_barrier_async |
在35s的時候打印的,是在上一個結(jié)束之后打印的 |
16:20:40.900 |
dispatch_async_after_1s |
在40s的時候打印的官疲,在上一個打印結(jié)束之后袱结,睡了4s后又睡了1s才打印的,所以和上一個打印相差5s=(4s+1s) |
4.dispatch_apply
執(zhí)行某個代碼片段N次
dispatch_apply(N,globalQ,^(size_t index){ //執(zhí)行N次 });
NSString類的實現(xiàn)
+(id)initWithCString:(c*****t char *)nullTerminatedCString encoding:(NSStringEncoding)encoding{ NSString *obj; obj = [self allocWithZone:NSDefaulMallocZone]; obj = [obj initWithCString:nullTerminatedCString encoding:encoding]; return AUTORELEASE(obj); }
static關(guān)鍵字的作用
- 函數(shù)體內(nèi)
static
變量的作用范圍為該函數(shù)體途凫,不同于auto
變量垢夹,該變量的內(nèi)存只被分配一次, 因此其值在下次調(diào)用時仍維持上次的值维费; - 在模塊內(nèi)的
static
全局變量可以被模塊內(nèi)所用函數(shù)訪問果元,但不能被模塊外其它函數(shù)訪問; - 在模塊內(nèi)的
static
函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用犀盟,這個函數(shù)的使用范圍被限制在聲明 它的模塊內(nèi)而晒; - 在類中的
static
成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝阅畴; - 在類中的
static
成員函數(shù)屬于整個類所擁有倡怎,這個函數(shù)不接收this
指針,因而只能訪問類的static
成員變量贱枣。
#import和#include的區(qū)別监署?
#import
是Objective-C
導(dǎo)入頭文件的語法,可保證不會重復(fù)導(dǎo)入纽哥。
-
#include
是C/C++
導(dǎo)入頭文件的語法钠乏, - 如果是
Objective-C
與C/C++
混編碼,對于C/C++
類型的文件春塌,還是使用#include
來引入晓避,這種寫法需要添加防重復(fù)導(dǎo)入的語法。
@class的作用
@class
一般用于頭文件中通過前向聲明只壳,就可以聲明了俏拱,但是在.m
文件中還是需要使用#import
進來的。它的作用只是前向聲明吕世。
property屬性的修飾符有什么樣的作用
參考鏈接來自標哥的技術(shù)博客:http://www.henishuo.com/ios-property/
getter=getName
彰触、setter=setName
:設(shè)置setter
與getter
的方法名
-
readwrite
、readonly
:設(shè)置可供訪問級別
-assign
:方法直接賦值命辖,不進行任何retain
操作况毅,為了解決原類型與環(huán)循引用問題 -
retain
:其setter
方法對參數(shù)進行release
舊值再retain
新值,所有實現(xiàn)都是這個順序 -
copy
:其setter
方法進行copy
操作尔艇,與retain
處理流程一樣尔许,先對舊值release
,再copy
出新的對象终娃,retainCount
為1味廊。這是為了減少對上下文的依賴而引入的機制。 -
nonatomic
:非原子性訪問,不加同步余佛, 多線程并發(fā)訪問會提高性能柠新。注意,如果不加此屬性辉巡,則默認是兩個訪問方法都為原子型事務(wù)訪問恨憎。
obj在編譯時和運行時分別時什么類型的對象
NSString *obj = [[NSData alloc] init];
在編譯時,我們所聲明的obj
是NSString *
類型郊楣,因此是NSString *
類型對象憔恳。在運行時,由于指針obj所指向的是NSData *
類型對象的內(nèi)存净蚤,因此實際上是NSData *
類型的對象钥组。
在編譯時,這一行代碼會轉(zhuǎn)換成類似這樣:
NSString *obj = ((id (*)(id, SEL))objc_msgSend)([NSData class], @selector(alloc)); obj = ((id (*)(id, SEL))objc_msgSend)((id)obj, @selector(init));
- 由于在編譯時今瀑,轉(zhuǎn)換成
id
程梦,因此可以用NSString *
指向NSData
對象,而id
是具備運行時
特性的放椰,因此在鏈接時作烟,通過id
的isa
指針可以找到其所屬的類,因此最終類型還是通過isa
確定其所屬類型砾医。
nil、Nil衣厘、NULL和NSNull區(qū)別
參考鏈接來自標哥的技術(shù)博客:http://www.henishuo.com/nil-nil-null-nsnull-difference/
-
NULL
-
NULL
在C
語言中如蚜,NULL
是無類型的,只是一個宏影暴,它代表空错邦。 - 像C語言中,我們定義了一個指針型宙,當我們使用完以后撬呢,通常會設(shè)置指向
NULL
。如果沒有設(shè)置妆兑,這個指針就成了所謂的野指針魂拦,然后其它地方不小心訪問了這個指針是很容易造成非法訪問的,常見的表現(xiàn)就是崩潰了搁嗓。 - 既然
Objective-C
是基于C
語言的面向?qū)ο笳Z言芯勘,那么也會使用到C
語言類型的指針,比如使用const char *
類型腺逛,判斷是否為空時荷愕,是使用p != NULL
來判斷的。
-
-
nil
- 對于我們
Objective-C
開發(fā)來說,nil
就代表((void *)0)
安疗。我們使用nil
表示Objective-C
對象為空抛杨,如NSString *str = nil
。
- 對于我們
Nil
對于我們
Objective-C
開發(fā)來說荐类,Nil
也就代表((void *)0)
蝶桶。但是它是用于代表空類的。比如Class *myClass = Nil;
NSNull
-
NSNull
是繼承于NSObject
的類型掉冶。它是很特殊的類真竖,它表示是空,什么也不存儲厌小,但是它卻是對象恢共,只是一個占位對象。- 比如說服務(wù)端接口中讓我們在值為空時璧亚,傳空讨韭。
NSDictionry *parameters = @{@"arg1" : @"value1",@"arg2" : arg2.isEmpty ? [NSNull null] : arg2};
- 比如說服務(wù)端接口中讓我們在值為空時璧亚,傳空讨韭。
總結(jié)
NULL是宏,是對于C語言指針而使用的癣蟋,表示空指針
nil是宏透硝,是對于Objective-C中的對象而使用的,表示對象為空
Nil是宏疯搅,是對于Objective-C中的類而使用的濒生,表示類指向空
NSNull是類類型,是用于表示空的占位對象幔欧,與JS或者服務(wù)端的null類似的含意