Effective Objective-C 2.0讀書筆記
第一章
- 消息結構和函數調用的區別:消息調用的語言,其運行時所執行的代碼由運行環境來決定;函數調用則有編譯器決定。
第二章
- 在類的頭文件中盡量少引用其他頭文件,用@class字段,減少編譯時間
第三章
- 多用@()來創建字面量
第四章
用#define會把所有的做替換,并且不會做類型判斷,也不會有同名警告。#define kTimeDuration 0.3
如果只要該編譯單元(.m文件)內使用。static const NSInteger kTimeDuration = 0.3;
如果要給外部可用,那么就這樣,命名要謹慎:
(.h)extern NSString * const EOCStringConstant;
(.m) NSString * const EOCStringConstant = @"Value";
第五章
用NS_ENUM和NS_OPTIONS定義的枚舉類型,并指明期底層數據類型,就能保證是用開發者選擇的底層數據類型來實現,而不會采用編譯器所選的類型。
如果想組合多個選項的枚舉,把值定義為2的冪,這樣就可以“按位或”起來。
第六章
- @property的各種語義聲明。在使用copy的時候,會拷貝一份副本,如果自己實現setter方法,自己要加上copy
第七章
- none
第八章
- 兩個對象相等,請重寫isEqual:方法
第九章
- 用類簇來屏蔽細節(大圖瀏覽器)
第十章
- 關聯對象,具體可見UIAlertView綁定block的demo,但是建議不要輕易使用該技術可能導致難以發現的bug
第十一章
- id returnValue = [someObject messageName:parameter];
其中,someObject叫做“接收者”(receiver),messageName叫做“選擇器”(selector), 選擇器和參數合起來稱為“消息(Message)”
編譯器會把它轉換為如下函數:
id returnValue = objc_msgSend(someObject, @selector(messageName:), parameter);
第十二章
- 消息轉發流程(三部曲):
- 先詢問接受者能否動態添加方法來處理未知的selector(unknown selector),這叫“動態方法解析”,會調用其所屬類的這個方法,取決于是類方法還是實例方法。此方案常用來實現@dynamic.
(BOOL)resolveInstanceMethod:(SEL)selector;
(BOOL)resolveClassMethod:(SEL)selector;
- 如果執行完第一步沒有結束,那么接受者自己就無法再以動態新增方法的手段來響應該消息了。此時Runtime會看看有沒有其他的對象來處理這條消息,轉發給其他的接受者來處理.下面的方法如果能找到備胎對象,就把備胎對象返回;如果沒有找到就返回nil。"備援接收者".模擬多重繼承。
- (id)forwardingTargetForSelector:(SEL)selector;
- 如果沒有備胎,那就把消息有關的全部細節都封裝到NSInvocation對象中,再給接收者最后一次機會來處理。會啟動“完整的消息轉發機制”。首先創建NSInvocation對象,把尚未處理的那條消息有關的全部細節都封于其中,此對象包含選擇器、目標(target)及參數。在觸發NSInvocation對象時,“消息派發系統(message-dispatch system)”會親自出馬,把消息指派給目標對象:
- (void)forwardInvocation:(NSInvocation *)invocation;
- 如果最后調用了NSObject類的方法還是搞不定,會繼續調用doesNotrecognizeSelector來拋出異常。
全過程圖示如下:或者見p49
- 具體的@dynamic示例見p48
第十三章
- Method Swizzling,可以給“完全不知道其具體實現的(completely opaque 完全不透明的)”黑盒方法添加日志記錄功能。不要濫用該方法
第十四章
每個對象結構體的首個成員是Class類的變量,該變量定義了對象所屬的類,即“isa”指針。Class對象也被定義為P57的結構體,結構體存放類的元數據“metadata”,該結構體的首個變量也是個isa指針,說明Class本身也是一個Objective-C對象。類對象的isa指針指向的類型是另外一個類,叫做元類“metaclass”,“類方法”(+號方法)就是定義在metaclass里面的。
isMemberOfClass判斷對象是否是一個特定具體類的實例。
isKindOfClass是判斷對象是否為某類或其派生類(子類)的實例。
第十五章
none
第十六章
none
第十七章
- 重寫description方法,可以利用NSDictionary的desccription方法來簡化
第十八章
none
第十九章/第二十章/第二十一章
none
第二十二章 copy
- copy和mutableCopy調用小結,copy返回不可變,mutableCopy返回可變。
針對不可變對象調用copy返回該對象本身(舊的),調用mutableCopy返回一個可變對象(新的);
針對可變對象調用copy返回一個不可變對象(新的),調用mutableCopy返回另外一個可變對象(新的)。
- @property
不可變類型屬性,推薦使用copy,因為假設該對象實際上指向的是一個mutable的對象,mutable對象的改變不會導致該對象的改變;假設指向的不是mutable的對象,那么copy和strong是等價,都是執行一次retain。
可變類型屬性,不能使用copy,因為copy產生的對象是一個不可變對象,跟屬性描述是沖突的。
- 深拷貝和淺拷貝的區別:
深拷貝:拷貝內容,且產生新對象。新對象計數器置為1,原對象計數器不變。副本對象改變時不改變原對象
淺拷貝:拷貝地址,不產生新對象。原對象計數器加1.只有一種情況是淺拷貝(不可變對象調用不可變的copy方法)
第二十三章
none
第二十四章
- 給一個比較大的類拆分成幾個功能區塊的小類,可以考慮使用分類
第二十五章
- 使用分類時,盡量要添加前綴
第二十六章
- 分類不能添加屬性,要使用關聯對象,或者@dynamic。所以關于對象的所有定義都要放在主接口中
第二十七章
看不懂怎么辦
第二十八章
通過協議來隱藏類名,類似泛型的思想
第二十九章
ARC是把幾乎所有的內存管理事宜都交給編譯器來決定,開發者只需專注業務邏輯
Setter方法中,必須先retain新值,release舊值,然后更新實例對象。順序很重要否則會變成懸掛指針
調用release會立刻遞減對象的引用計數,調用autorelease會在稍后遞減引用計數,通常在下一次事件循環(event loop)時遞減,不過也有可能執行得更早些(34章)
內存泄露:沒有正確釋放該釋放的內存(已經不再使用的內存)
第三十章
使用ARC要注意,引用計數實際上還是要執行的,只不過保留和釋放操作現在是由ARC自動為我們添加,并且ARC添加的是底層的C語言函數,如objc_retain。
ARC只負責管理Objective-C對象的內存,CoreFoundation對象不歸ARC管理,開發者必須適時調用CFRetain、CFRelease.
第三十一章
- ARC會通過自動生成的.cxx_destruct方法在dealloc中自動添加釋放代碼。CoreFoundation對象必須手工釋放。
第三十二章
- none
第三十三章
- 用弱引用避免循環引用
第三十五章
不是很明白
第三十六章
- 不要使用retainCount
第三十七章、第三十八章
- 定義block的時候,他的內存區域是分配在棧上的。就是說,塊只在定義它的范圍內有效。比如:
void (^block);
if (A) {
block = ^{ NSLog(@"A")};
} else {
block = ^{ NSLog(@"B")};
}
這個block很可能會被回收,因為只在if或者else里面有效。
正確的做法:
void (^block);
if (A) {
block = [^{ NSLog(@"A")} copy];
} else {
block = [^{ NSLog(@"B")} copy];
}
- block會把局部變量捕獲,block會在
定義時
就把當時的局部變量值捕獲進來;如果想在運行時
再捕獲,就加上__block
第三十九、四十章
none
第四十一章
- 多用派發隊列表述同步語義,比@synchronized和NSLock要好