二味赃、對(duì)象言秸、消息吟秩、運(yùn)行期
6. 理解“屬性”這一概念
- 使用@property 語法來定義對(duì)象中封裝的數(shù)據(jù)
- 通過“特質(zhì)” 來制定存儲(chǔ)數(shù)據(jù)所需的正確語義
- 在設(shè)置屬性所對(duì)應(yīng)的實(shí)例變量時(shí)仆百,一定要遵從該屬性所聲明的語義。
- 開發(fā)iOS : 使用nonatomic 屬性堵腹。atomic 會(huì)影響性能梢杭。
實(shí)例變量訪問方式: 存取方法(access method)(讀取)+ 獲取方法(getter)(寫入)
定義實(shí)例:編譯器會(huì)把其替換成“偏移量”(offset)== "硬編碼"(hardcode)
編譯器計(jì)算出來的偏移量秸滴,在修改類定義后必須重新編譯武契。
Object-C 的偏移量存儲(chǔ)交給“類對(duì)象來處理”
@property 語法:
"點(diǎn)語法" == "存取方法"
自動(dòng)編寫訪問屬性的方法-> “自動(dòng)合成” autosynthesis
Person* aPerson = [Person new];
aPerson.firstName = @"Bob";//Same as
[aPerson setFirstName:@"Bob"];
NSString* lastName = aPerson.lastName;//Same as
NSString* lastName = [aPerson lastName];
@synthesize :去除生成變量名的下劃線。
@dynamic 阻止自動(dòng)合成方法創(chuàng)建
屬性特質(zhì)
原子性(atomic):某操作具有整體性荡含,系統(tǒng)其他部分無法觀察到其中間的操作步驟咒唆,只能看到操作前和操作結(jié)果。 其他命名:(獲取器释液,設(shè)置器全释,保有)。
OC 默認(rèn)情況下 是“原子的”
讀/寫權(quán)限
1.readwrite :擁有 getter误债、 setter2.readoly : 僅擁有獲取方法浸船。
內(nèi)存管理語義:
Name | 語義 |
---|---|
assign | “純量類型” (scalar type、CGFloat寝蹈、 NSInterger) |
unsafe_unretained | == assign 但適用于 ”對(duì)象類型“(object type) “非擁有關(guān)系” 當(dāng)對(duì)象被摧毀時(shí)候李命,屬性值不會(huì)清空。 |
strong | “擁有關(guān)系“ 1.設(shè)置新職時(shí):1.保留新值 2.釋放舊值 3.把新值設(shè)置上去 |
copy | == strong 但是設(shè)置方法不保留新值箫老,而是“拷貝”(copy)封字。 |
weak | “非擁有關(guān)系” 1.不保留新值 2.不釋放舊值。對(duì)象遭到摧毀時(shí)耍鬓,屬性值也會(huì)清空(nil out)阔籽。 |
7. 在對(duì)象內(nèi)部盡量直接訪問實(shí)例變量
寫法: 直接訪問實(shí)例變量 _屬性名 ; 通過屬性:self.屬性名
- 對(duì)象內(nèi)部提取牲蜀,應(yīng)該通過直接訪問實(shí)例變量來讀笆制,通過屬性來寫。 <_objc(直接訪問) & self.objc >
- 在初始化和dealloc方法中涣达,都應(yīng)該直接通過實(shí)例變量來讀寫數(shù)據(jù) <_objc>
- 惰性初始化配置某份數(shù)據(jù)在辆,需通過屬性來讀寫數(shù)據(jù) <self.objc>
8. 理解“對(duì)象同等性”這一個(gè)概念
- 檢測(cè)對(duì)象的等同性: 1. isEqual: 2. hash
- 相同對(duì)象必須具有相同的哈希碼, 但兩個(gè)哈希碼相同的對(duì)象未必相同峭判。
- 不要盲目逐條檢測(cè)每條屬性开缎, 而是應(yīng)該按具體需求制定檢測(cè)方案。
- hash 方法: 使用計(jì)算速度快而且哈希碼碰撞低的算法林螃。
9. 以“類族模式” 隱藏實(shí)現(xiàn)細(xì)節(jié)
- 類族模式可以實(shí)現(xiàn)細(xì)節(jié)隱藏在一套簡(jiǎn)單的公共接口后面奕删。
- 系統(tǒng)框架中經(jīng)常使用類族
- 從類族的公共抽象基類中繼承子類時(shí) 要小心,應(yīng)優(yōu)先閱讀開發(fā)文檔疗认。
工廠模式(Factory pattern) :基類實(shí)現(xiàn)一個(gè)”類方法“完残、子類繼承基類 跟根據(jù)“類方法” 實(shí)現(xiàn)類實(shí)例伏钠。
10. 在既有類中使用關(guān)聯(lián)對(duì)象存放自定義數(shù)據(jù)
- 使用“關(guān)聯(lián)對(duì)象” 機(jī)制把兩個(gè)對(duì)象連接起來
- 定義關(guān)聯(lián)對(duì)象時(shí)可指派對(duì)象內(nèi)存管理語義 == 屬性
- 一般情況下不使用“關(guān)聯(lián)對(duì)象”, 只有在其他做法不可行時(shí)使用谨设,因?yàn)檫@種做法通常會(huì)引入難以查找的bug熟掂。
對(duì)象中存放相關(guān)需求:
- 一般情況下,從對(duì)象所屬的類中繼承一個(gè)子類扎拣,然后改用這個(gè)子類對(duì)象赴肚。
- 無法創(chuàng)建子類對(duì)象的情況下,使用 “關(guān)聯(lián)對(duì)象” (Associated Object)二蓝。
“關(guān)聯(lián)對(duì)象 ”存儲(chǔ)語義:
關(guān)聯(lián)類型 | 等效的@property屬性 |
---|---|
OBJC_ASSOCIATION_ASSIGN |
assign |
OBJC_ASSOCIATION_RETAIN_NONATOMIC |
nonatomic,retain |
OBJC_ASSOCIATION_COPY_NONATOMIC |
nonatomic,copy |
OBJC_ASSOCIATION_RETAIN |
retain |
OBJC_ASSOCIATION_COPY |
copy |
方法:
#import <objc/runtime.h>
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
11. 理解objc_msgSend 的作用
- 消息構(gòu)成: 接收者誉券、選擇子、參數(shù)刊愚。 給某對(duì)象“發(fā)送消息”(invoke a messge) == 在該對(duì)象上“調(diào)用方法”踊跟。
- 發(fā)送給某對(duì)象的消息全部有“動(dòng)態(tài)消息派發(fā)系統(tǒng)”(dynamic message despatch system)來處理,該系統(tǒng)會(huì)查處對(duì)應(yīng)的方法鸥诽。
OC商玫、對(duì)象的方法調(diào)用: “傳遞消息” (pass a message)。消息:“名稱”(name)或者 “選擇子”(selecor)牡借,可以接受參數(shù)拳昌,可能有返回值。
C蓖捶、靜態(tài)綁定(static biding)編譯期就決定了運(yùn)行時(shí)所應(yīng)調(diào)用的函數(shù)地回。
sendMsg 操作流程:
- 接收著所屬類里搜尋“方法列表”(list of methods)
- 找到與之相匹配的方法名就跳轉(zhuǎn)至其實(shí)現(xiàn)代碼
- 找不到 沿著集成體系往上查找扁远,直到找到為止俊鱼。
- 還是找不到-> 執(zhí)行“消息轉(zhuǎn)發(fā)”(message forwarding);
12. 理解消息轉(zhuǎn)發(fā)機(jī)制
- 消息轉(zhuǎn)發(fā)機(jī)制觸發(fā):對(duì)象無法響應(yīng)某個(gè)選擇子
- 1.動(dòng)態(tài)方法解析 -> 2.轉(zhuǎn)交給其他對(duì)象解析 -> 3.完整的消息轉(zhuǎn)發(fā)機(jī)制 [3個(gè)步驟 其中一個(gè)步驟完成就不會(huì)啟動(dòng)下一個(gè)步驟]
消息轉(zhuǎn)發(fā)流程:

13. 用“方法調(diào)試技術(shù)” 調(diào)試 “黑盒方法”
- 運(yùn)行期,可以向類中新增或者替換選擇子所對(duì)應(yīng)的方法實(shí)現(xiàn)
- 通關(guān) “方法調(diào)試”向原有實(shí)現(xiàn)中添加新的功能畅买。
- 一般調(diào)試的時(shí)候使用并闲,不宜濫用。
方法調(diào)配(method swizzling):object-c 對(duì)象受到消息后谷羞,只有在運(yùn)行期才能解析帝火。利用這一特性覆寫SEL-IMP 關(guān)系,就能改變這個(gè)類的本身的功能湃缎。
動(dòng)態(tài)消息派發(fā)系統(tǒng) 根據(jù) :類的方法列表會(huì)把選擇子的名稱映射到相關(guān)的實(shí)現(xiàn)上犀填。
IMP: 函數(shù)方法指針。 id (* IMP)(id, SEL, ...)
類的選擇子映射表 圖1:

開發(fā)者幾個(gè)開發(fā)方向:1. 新增選擇子 2. 改變選擇子所對(duì)應(yīng)的方法實(shí)現(xiàn) 3. 交換兩個(gè)選擇子所映射到的指針嗓违。
改變后映射表 圖2:

交換方法:Void method_exchangeImplementations(Method m1, Method m2)
獲取相關(guān)的方法: Mehod class_getInstanceMethod(Class aClass, SEL aSelector)
Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));
Method swappedMethod = class_getInstanceMethod([NSString class], @selector(uppercaseString));
method_exchangeImplementations(originalMethod, swappedMethod);
調(diào)試方案:
- 添加一個(gè)分類(category) 一個(gè)新方法
- 與現(xiàn)有的方法互換
- 可以實(shí)現(xiàn)日志九巡、 適用于短時(shí)間現(xiàn)有版本方法更改問題。
14. 理解“類對(duì)象”的用意
- 沒個(gè)實(shí)例都有一個(gè)指向Class對(duì)象的指針蹂季,用以表明其類型冕广,這些Class對(duì)象構(gòu)成類的繼承體系疏日。 [Class isa]
- 使用類型信息查詢方法來探知無法在編譯器確定類型的對(duì)象。
- 盡量使用類型信息查詢方法來確定對(duì)象類型撒汉,不要直接比較類對(duì)象沟优,因?yàn)槟承?duì)象可能實(shí)現(xiàn)了消息轉(zhuǎn)發(fā)功能。
"isMemberOfCalss:" 判定對(duì)象是否為某個(gè)對(duì)象的實(shí)力
"isKindOfClass:" 對(duì)象是否是這個(gè)類或者其派生類的實(shí)力睬辐。
//判斷對(duì)象是否是某個(gè)類的實(shí)例
if ([objec class] == [EOCSomeClass class]){
//'objec' is an instance of EOCSomeClass
}