分類
分類的作用
分解體積龐大的類文件
為系統類添加方法
聲明私有方法
把Framework的私有方法公開
分類添加過程
在程序運行時候,runtime會把分類的實例方法等信息合并到類對象的實例方法列表中,會把分類的類方法合并到元類對象的類方法列表中(在原方法之前)。
以添加實例方法為例:
運行時候,會遍歷分類列表,拿到每一個分類的實例方法列表
分類能添加成員變量嗎?
不能。只能通過關聯對象(objc_setAssociatedObject)來模擬實現成員變量,但其實質是關聯內容,所有對象的關聯內容都放在同一個全局容器哈希表中:AssociationsHashMap,由AssociationsManager統一管理。
#關聯對象: 使用objc_setAssociatedObject函數可以給某個對象關聯其他的對象。
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
#獲取關聯的對象: 使用objc_getAssociatedObject函數可以通過鍵來取出某個對象的關聯對象。
id objc_getAssociatedObject(id object, const void *key)
#移除關聯的對象:使用objc_removeAssociatedObjects函數可以移除某個對象身上的所有關聯的對象。
void objc_removeAssociatedObjects(id object)
?
?
?
擴展
一般用擴展做什么?
聲明私有屬性,聲明方法(沒什么意義),聲明私有成員變量
擴展的特點
編譯時決議,只能以聲明的形式存在,多數情況下寄生在宿主類的.m中,不能為系統類添加擴展。
分類跟擴展的區別
擴展:在編寫完分類文件后,直接把分類內容添加到相關的宿主類上。
分類:是在運行時使用runtime把分類的內容添加到宿主類上。
?
?
?
代理
代理是一種設計模式,以@protocol形式體現。
一般是一對一傳遞,一般以weak關鍵詞以規避循環引用。
本質是獲得對象,調用方法返回數據。
?
?
?
通知
使用觀察者模式來實現的用于跨層傳遞信息的機制。
傳遞方式是一對多的。
原理是在通知中心維護一個map表,key為通知的名稱,value為observer。本質為持有對象,所以在不用時,需要釋放對象。
?
?
?
KVO
使用觀察者設計模式,使用isa混寫技術。
當A類實例被KVO監聽時,Runtime會轉建一個繼承自A類的新類NSKVONotifying_A,并重寫被觀察屬性的setter和getter方法。如果代碼中有創建NSKVONotifying_A類,注冊A類KVO時會崩潰。
何時觸發:
使用setter方法改變值時,會觸發KVO;
使用KVC setValue:forKey:改變值時,會觸發KVO;
成員變量直接修改,不會觸發KVO,需手動添加willChangeValueForKey和didChangeValueForKey方法才會觸發;
- (void)setName:(NSString *)newName {
[self willChangeValueForKey:@"name"]; //KVO 在調用存取方法之前總調用
[super setValue:newName forKey:@"name"]; //調用父類的存取方法
[self didChangeValueForKey:@"name"]; //KVO 在調用存取方法之后總調用
}
~
~
~
KVC
KVC的全稱是Key-Value Coding,俗稱“鍵值編碼”,可以通過一個key來訪問某個屬性。KVC的操作方法由NSKeyValueCoding提供,而他是NSObject的類別,也就是說ObjC中幾乎所有的對象都支持KVC操作。
常用方法
獲取值的方法
valueForKey:,傳入NSString屬性的名字。
valueForKeyPath:,傳入NSString屬性的路徑,xx.xx形式。
valueForUndefinedKey它的默認實現是拋出異常,可以重寫這個函數做錯誤處理。
修改值的方法
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:
setValue:forKey的搜索過程:
- 首先搜索set<Key>:方法
如果成員用@property,@synthsize處理,因為@synthsize告訴編譯器自動生成set<Key>:格式的setter方法,所以這種情況下會直接搜索到。
注意:這里的<Key>是指成員名,而且首字母大寫。 - 上面的setter方法沒有找到,如果類方法accessInstanceVariablesDirectly返回YES(注:這是NSKeyValueCodingCatogery中實現的類方法,默認實現為返回YES)。
那么按_<key>,_is<Key>,<key>,is<key>的順序搜索成員名。 - 如果還是沒有找到設置成員的值,就會調用setValue:forUndefinedKey:。
- 如果沒有重寫setValue:forUndefinedKey程序會馬上崩潰。
?
?
?
屬性關鍵字
1.讀寫權限:readonly,readwrite(默認)
2.原子性: atomic(默認),nonatomic。atomic讀寫線程安全,但效率低,而且不是絕對的安全,比如如果修飾的是數組,那么對數組的讀寫是安全的,但如果是操作數組進行添加移除其中對象的還,就不保證安全了。
3.引用計數:
retain/strong:引用計數加1
assign:修飾基本數據類型,修飾對象類型時,不改變其引用計數,會產生懸垂指針,修飾的對象在被釋放后,assign指針仍然指向原對象內存地址,如果使用assign指針繼續訪問原對象的話,就可能會導致內存泄漏或程序異常
weak:不改變被修飾對象的引用計數,所指對象在被釋放后,weak指針會自動置為nil
copy:分為深拷貝和淺拷貝
淺拷貝:對內存地址的復制,讓目標對象指針和原對象指向同一片內存空間會增加引用計數
深拷貝:對對象內容的復制,開辟新的內存空間
可變對象的copy和mutableCopy都是深拷貝
不可變對象的copy是淺拷貝,mutableCopy是深拷貝
copy方法返回的都是不可變對象
@property (nonatomic, copy) NSMutableArray * array;這樣寫有什么影響?
因為copy方法返回的都是不可變對象,所以array對象實際上是不可變的,如果對其進行可變操作如添加移除對象,則會造成程序crash。
?
?
?
參考:Objective_C語言特性:分類、擴展
參考: iOS開發-OC篇-KVC詳解