52個(gè)有效方法閱讀筆記(五)

1.理解"塊"這一概念

  • 塊是 C,C++,Object-C 中的語(yǔ)法閉包.
  • 塊可以接收參數(shù),也可以返回參數(shù).
  • 如果塊里捕獲的是對(duì)象類型的變量,那么塊就會(huì)自動(dòng)保存它,系統(tǒng)在釋放這個(gè)塊的時(shí)候,也會(huì)將其一并釋放.
  • 因?yàn)槊總€(gè)實(shí)例變量的個(gè)數(shù)及對(duì)象所包含的關(guān)聯(lián)數(shù)據(jù)互不相同,所以每個(gè)對(duì)象所占內(nèi)存區(qū)域也有大有小.
  • 在塊里面捕獲所持有的對(duì)象,拷貝的并不是對(duì)象本身,而是指向?qū)ο蟮闹羔樧兞?
  • 除了"棧塊"和"堆塊"之外,還有一種叫"全局塊(gloab block)".全局塊的拷貝操作是個(gè)空的操作,因?yàn)槿謮K決不可能為系統(tǒng)所回收.實(shí)際上相當(dāng)于單利.
  • 塊可以分配在堆或棧上,也可以是全局的.分配在棧上的塊可拷貝到堆里,這樣的話,就和標(biāo)準(zhǔn)的 Object-C 對(duì)象一樣,具備引用計(jì)數(shù)了.

2.為常用的塊類型創(chuàng)建 typedef

  • 以 typedef 重新定義塊類型,可令塊變量用起來(lái)更加簡(jiǎn)單.
  • 定義新類型時(shí),必須遵從現(xiàn)有的,命名習(xí)慣,勿使其名稱與別的類型相沖突.
  • 每個(gè)塊都具備其"固定類型(inherent type)",因而可將其賦值給適當(dāng)類型的變量.
  • 使用類型定義后,當(dāng)你打算重構(gòu)塊的類型簽名時(shí)會(huì)很方便.
  • 最好在使用塊類型的類中定義這些 typedef, 而且還應(yīng)該把這個(gè)類的名字加在由 typedef 所定義的新類型名前面,這樣就可以闡明塊的用途.
  • 不妨為同一個(gè)塊簽名定義多個(gè)類型別名.如果要重構(gòu)的代碼使用了塊類型的某個(gè)別名,那么只需修改相應(yīng) typedef 中的塊簽名,無(wú)須改動(dòng)其他 typedef.

3.用 hander 塊降低代碼分散程度

  • 在創(chuàng)建對(duì)象時(shí),可以使用內(nèi)聯(lián)的 hander 塊將相關(guān)業(yè)務(wù)邏輯一并聲明.
  • 在有多個(gè)實(shí)例要監(jiān)控時(shí),如果采用委托模式,那么經(jīng)常需要根據(jù)傳入的對(duì)像來(lái)切換,而若改用 hander 塊來(lái)實(shí)現(xiàn),則可直接將塊與相關(guān)對(duì)象放在一起.
  • 設(shè)計(jì) API 時(shí)如果用到了 hander 塊,那么可以增加一個(gè)參數(shù),使調(diào)用者可通過(guò)此參數(shù)來(lái)決定應(yīng)該吧塊安排在哪個(gè)隊(duì)列上執(zhí)行.

4.用塊引用其所屬對(duì)象時(shí)不要出現(xiàn)保留環(huán)

  • 如果塊所捕獲的對(duì)象直接或間接的保留了塊本身,那么就得當(dāng)心保留環(huán)的問(wèn)題.
  • 一定要找個(gè)適當(dāng)?shù)臅r(shí)機(jī)解除保留環(huán),而不能把責(zé)任退給 API 的調(diào)用者.

4.多用派發(fā)隊(duì)列,少用同步鎖

  • @synchronized 屬性原子性內(nèi)部實(shí)現(xiàn)鎖,可以提供某種程度的"線程安全(therad safety)",但卻無(wú)法保證訪問(wèn)該對(duì)象時(shí)絕對(duì)是線程安全.
  • 簡(jiǎn)單而高效的代替同步塊或鎖對(duì)象的方法,就是使用"串行同步隊(duì)列(serial synchoronization queue)".
  • 在并發(fā)隊(duì)列中,柵欄塊必須單獨(dú)執(zhí)行,不能與其他塊并行.這支隊(duì)并發(fā)隊(duì)列有意義,因?yàn)榇嘘?duì)列中的塊總是按順序逐個(gè)來(lái)執(zhí)行的.
  • 派發(fā)隊(duì)列可用來(lái)表示同步語(yǔ)義(synchroniztion semantic),這種做法要比使用@ synchronized 塊或 NSLock 對(duì)象更簡(jiǎn)單.
  • 將同步與異步派發(fā)結(jié)合起來(lái),可以實(shí)現(xiàn)與普通加鎖機(jī)制一樣的同步操作,而這么做卻不會(huì)阻塞執(zhí)行異步派發(fā)線程.
  • 使用同步隊(duì)列及柵欄塊,可以令同步行為更加高效.

5.多用 GCD, 少用 performSelector 方法

  • 用 performSelector:系類方法,編譯器并不知道將要調(diào)用的選擇子是什么,因此,也就不了解其方法的簽名及返回值,甚至連是否有返回值都不清楚.而且,由于編譯器不知道方法名,所以就沒(méi)辦法運(yùn)用 ARC 的內(nèi)存管理規(guī)則來(lái)判定返回值是不是應(yīng)該釋放.鑒于此, ARC 采用了比較謹(jǐn)慎的做法,就是不加添釋放操作.然而這么做很可能導(dǎo)致內(nèi)存泄露,因?yàn)榉椒ㄔ诜祷貙?duì)象時(shí)有可能已經(jīng)將其保留了.
  • performSelector系類方法所能處理的選擇子太過(guò)局限了,選擇子的返回值類型及發(fā)送給方法的參數(shù)個(gè)數(shù)都受限制.
  • 如果想把任務(wù)放到另一個(gè)線程上執(zhí)行,那么最好不要使用 performSeletor 系列方法,而是應(yīng)該把任務(wù)封裝到塊面,然后調(diào)用大中樞派發(fā)機(jī)制的相關(guān)方法來(lái)實(shí)現(xiàn).

6.掌握 GCD 及操作隊(duì)列的使用時(shí)機(jī)

  • GCD 是純 C 的 API, 而操作隊(duì)列是 Object-C 的對(duì)象.咋 GCD 中,任務(wù)用塊來(lái)表示,而快是輕量級(jí)的數(shù)據(jù)結(jié)構(gòu).與之相反,"操作(operation)"則是更為重量級(jí)的 Object-C 的對(duì)象.

  • 使用 NSOperationQueue 及 NSOperation 的好處:

    a.取消某個(gè)操作,在任務(wù)執(zhí)行之前,可以在 NSOperation 對(duì)象上調(diào)用 cancel 方法.不過(guò),已經(jīng)啟動(dòng)的任務(wù)無(wú)法取消.

    b.制定操作間的依賴關(guān)系.一個(gè)操作可以依賴其它多個(gè)操作.

    c. 通過(guò)鍵值觀察機(jī)制監(jiān)控 NSOperation 對(duì)象的屬性.例:isCancelled 屬性來(lái)判斷任務(wù)是否取消. isFinished 屬性判斷任務(wù)是否完成.

    d. 制定操作的優(yōu)先級(jí).

    e. 重用 NSOperation 對(duì)像.

  • 在解決多線程與任務(wù)管理問(wèn)題時(shí),派發(fā)隊(duì)列并非唯一的方案.

  • 操作隊(duì)列提供了一套高層的 Object-C API,能實(shí)現(xiàn)純 GCD 所具備的大部分功能,而且還能完成一些更為復(fù)雜的操作,那些操作若改用 GCD 來(lái)實(shí)現(xiàn),則需另外編寫代碼.

7.通過(guò) Dispath Group 機(jī)制,根據(jù)系統(tǒng)資源狀態(tài)來(lái)執(zhí)行任務(wù)

  • dispath_apply 所用的隊(duì)列可以是并發(fā)隊(duì)列或者串行隊(duì)列. disapath_apply 會(huì)阻塞線程,直到所有的任務(wù)都執(zhí)行完畢為止.
  • 假如把塊派發(fā)給了當(dāng)前隊(duì)列(或者體系中高于當(dāng)前隊(duì)列的某個(gè)串行隊(duì)列),就會(huì)導(dǎo)致死鎖.若想在后臺(tái)執(zhí)行任務(wù),則應(yīng)使用 dispath group.
  • 一系列任務(wù)可歸入一個(gè) dispath group 之中.開發(fā)者可以在這組任務(wù)執(zhí)行完畢時(shí)獲取通知.
  • 通過(guò) dispath group,可以在并發(fā)式派發(fā)隊(duì)列里同時(shí)執(zhí)行多項(xiàng)任務(wù).此時(shí) GCD 會(huì)根據(jù)系統(tǒng)的資源來(lái)調(diào)度這些并發(fā)的任務(wù).開發(fā)者若自己來(lái)實(shí)現(xiàn)此功能,則需編寫大量代碼.

8.使用 dispath_once 來(lái)執(zhí)行只需運(yùn)行一次的線程安全代碼.

  • 經(jīng)常需要編寫"只需要執(zhí)行一次的線程安全代碼(thread-safe single-code execution)".通過(guò) GCD 所提供的 dispath_once 函數(shù),很容易就能實(shí)現(xiàn)此功能.
  • 標(biāo)記應(yīng)該聲明在 staic 或者 global 作用域中,這樣的話,在把只要執(zhí)行一次的塊傳給 dispath_once 函數(shù)時(shí),傳進(jìn)去的標(biāo)示也是相同的.

9.不要使用 dispath_get_current_queue

  • dispath__get_ _ current_queue 在iOS6.0版本起,已經(jīng)正式廢棄使用了,不過(guò) macOs 系統(tǒng)在10.8版本也尚未廢棄.雖然說(shuō)如此,但是在 macOs 系統(tǒng)還是要避免使用它.
  • dispath__get_ _ current_queue 函數(shù)行為常常與開發(fā)者所預(yù)期的不同,此函數(shù)廢棄,只應(yīng)用作調(diào)試.
  • 由于派發(fā)隊(duì)列是按層級(jí)來(lái)組織的,所以無(wú)法但用某個(gè)隊(duì)列對(duì)象來(lái)描述"當(dāng)前隊(duì)列"這一概念.
  • dispath__get_ _ current_queue 函數(shù)用于解決由不可重入的代碼所引發(fā)的死鎖,然而能用此函數(shù)解決的問(wèn)題,通常也能改用"隊(duì)列特定數(shù)據(jù)"來(lái)解決.
  • dispath__queue_ _ set_specific "隊(duì)列特定數(shù)據(jù)",用來(lái)給相應(yīng)隊(duì)列添加信息.
void dispath_queue_set_specific(dispath_queue_t queue,
                                const void *key,
                                void *context,
                                dispath_funcation_t destructor);

queue:設(shè)置信息的隊(duì)列;

key:函數(shù)就是按照這個(gè) key 來(lái)比較鍵的.

context:對(duì)隊(duì)列特定數(shù)據(jù)的關(guān)聯(lián)引用,這個(gè)對(duì)象的內(nèi)存管理要自己處理;

destructor:解析構(gòu)造函數(shù),對(duì)于給定的鍵來(lái)說(shuō),當(dāng)隊(duì)列所占內(nèi)存為系統(tǒng)所回收,或者有新的值與鍵相關(guān)聯(lián)時(shí),原有的值對(duì)象就會(huì)被移除,而析構(gòu)函數(shù)也會(huì)此時(shí)運(yùn)行.dispath__funcation _t 類型的定義如下:

typedef void (*dispath_funcation_t)(void *)

由此可見,析構(gòu)函數(shù)只能帶一個(gè)指針參數(shù)且返回值為 void.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市榨为,隨后出現(xiàn)的幾起案子谆奥,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件偷厦,死亡現(xiàn)場(chǎng)離奇詭異展氓,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)割去,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門窟却,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人呻逆,你說(shuō)我怎么就攤上這事夸赫。” “怎么了咖城?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵茬腿,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我宜雀,道長(zhǎng)切平,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任辐董,我火速辦了婚禮悴品,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己苔严,他們只是感情好菇存,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邦蜜,像睡著了一般依鸥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悼沈,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天贱迟,我揣著相機(jī)與錄音,去河邊找鬼絮供。 笑死衣吠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的壤靶。 我是一名探鬼主播缚俏,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼贮乳!你這毒婦竟也來(lái)了忧换?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤向拆,失蹤者是張志新(化名)和其女友劉穎亚茬,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浓恳,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡刹缝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颈将。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梢夯。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖晴圾,靈堂內(nèi)的尸體忽然破棺而出颂砸,到底是詐尸還是另有隱情,我是刑警寧澤疑务,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布沾凄,位于F島的核電站,受9級(jí)特大地震影響知允,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜叙谨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一温鸽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦涤垫、人聲如沸姑尺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至榆芦,卻和暖如春柄粹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背匆绣。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工驻右, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人崎淳。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓堪夭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拣凹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子森爽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容