第6條: 理解"屬性"這一概念
- "屬性"是OC 的一項特性, 用來封裝對象中的數據.
- OC 對象通常會把所需要的數據保存為各種實例變量.
屬性特質
- 原子性
- 讀/寫權限
- readwrite
- readonly
- 內存管理語義
- assign: 針對"純量類型", 例如 CGFloat 的簡單賦值操作
- strong: 定義一種"擁有關系", 先保留新值, 并釋放舊值, 然后再將新值設置上去
- weak: 定義"非擁有關系", 既不保留新值, 也不釋放舊值. 跟 assign 類似, 在屬性所指的對象遭到摧毀時, 屬性值會被清空
- unsafe_unretained: 語義和 assign 相同, 但是它適用于"對象類型", 表達一種"非擁有關系", 當目標對象摧毀時, 屬性值不會被清空
- copy: 表達的所屬關系與 strong 類似. 并不保留新值, 而是將其拷貝.
- 方法名
- getter=<name> : 指定"獲取方法"的方法名. 例如:@property (nonatomic, getter=isOn) BOOL on;
- setter=<name> : 指定"設置方法"的方法名. 用法不常見.
要點總結
- 可以用@propetry 語法來定義對象中所封裝的數據
- 通過"特質"來指定存儲數據所需要的正確語義
- 在設置屬性所對應的實例變量時, 一定要遵從該屬性所聲明的語義\
- iOS 開發時應該使用 nonatomic 屬性, 因為 atomic 屬性會嚴重影響性能
第7條: 在對象內部盡量直接訪問實例變量
要點
- 在對象內部讀取數據時, 應該直接通過實例變量來讀, 而寫入數據時, 則應該通過屬性來寫
- 在初始化方法和 dealloc 方法中, 總是應該通過實例變量來讀寫數據
- 有時候會使用懶加載初始化技術配置某份數據, 這種情況下, 需要通過屬性來讀取數據.
第8條: 理解"對象等同性"這一概念
按照 == 操作符比較出來的結果未必是我們想要的, 以為該操作符比較的是兩個指針本身, 而不是其所指向的對象. 應該使用NSObject 協議中聲明的"isEqual"方法來判斷兩個對象的等同性.
一般來說, 兩個類型不同的對象總是不相等的.
NSObject 協議中有兩個用于判斷等同性的關鍵方法:
- (BOOL)isEqual:(id)object;
- (NSUinteger)hash;
NSObject 類對這兩個方法的默認實現是: 當且僅當"指針值"完全相等時, 這兩個對象才相等. 如果"isEqual:"方法判斷兩個對象相等, 那么其 hash 方法也必須返回同一個值. 但是, 如果兩個對象的 hash 方法返回同一個值, 那么"isEqual:"方法未必會認為兩者相等.
特殊類所具有的等同性判定方法
在編寫判定方法時, 也應一并復寫"isEqual:"方法, 后者的常見實現方式為: 如果受測的參數與接收該消息的對象都屬于同一個類, 那么就調用自己編寫的判定方法, 否則就交由超類來判斷.
等同性判定的執行深度
是否需要在等同性判定方法中檢測全部字段取決于受測對象. 只有類的編寫者才可以確定兩個對象實例在何種情況下應判定為相等.
要點
- 若想監測對象的等同性, 請提供"isEqula:" 與 hash 方法
- 相同的對象必定具有相同的哈希碼, 但兩個哈希碼相同的對象未必相同
- 不要盲目逐個監測每條屬性, 而應該根據具體需求來制定檢測方案
- 便攜 hash 方法時, 應該使用計算速度快而且哈希碼碰撞幾率低的算法
第9條: 以"類族模式"隱藏實現細節
"類族"是一種很有用的模式, 可以隱藏"抽象基類"背后的實現細節.
要點:
- 類族模式可以把實現細節隱藏在一套簡單的公開接口后面
- 系統框架中經常使用類族
- 從類族的公開抽象基類中繼承子類時要當心, 若有開發文檔, 則需要首先閱讀
第10條: 在既有類中使用關聯對象存放自定義數據
要點:
- 可以通過"關聯對象"機制把兩個對象聯系起來
- 可以關聯對象時可指定內存管理語義, 用以模仿定義屬性時所采用的"擁有關系"和"非擁有關系"
- 只有在其他方法不可行的情況下才應選用關聯對象, 因為這種做法通常會引入難以查找的 bug
第11條: 理解 objc_msgSend 的作用
要點:
- 消息油接收者, 選擇器,及參數組成. 給某對象"發送消息"也就是相當于在該對象上"調用方法"
- 發給某對象的全部消息都由"動態消息派發系統"來處理, 該系統會查出對應的方法, 并執行其代碼