分類
1、你用分類都做了哪些事情?
-聲明私有方法(比如定義一個分類,只有頭文件放到對應宿主.m里,滿足私有方法的聲明和使用,不暴露具體實現。)
-分解體積龐大的類文件
-把Framework的私有方法公開
2、特點
-運行時決議,指的是在運行時,通過runtime將分類里面的內容添加到宿主類里面,當我們在編寫或者編好分類文件后,它并沒有把寫好的內容添加到宿主類上,這個時候宿主類還沒有分類中的方法,而是在運行時通過runtime把分類中的方法添加至宿主類上,這是分類的最大特點,也是分類和擴展的最大區別。
-可以為系統類添加分類,而擴展是不能給系統類添加擴展的。
3、分類中都可以添加哪些內容?
-實例方法
-類方法
-協議
-屬性(只聲明了get和set方法,并沒有實現get和set方法,也沒有生成實例變量)
4、加載調用棧
-分類添加的方法可以“覆蓋”原類方法(當然不是真的覆蓋)
-兩個分類,里面有一個同名方法,最后編譯的分類里面的方法被調用。
-名字相同的分類會引起編譯報錯
擴展
1、問題:一般用擴展做什么?
-聲明私有屬性
-聲明私有方法
-聲明私有成員變量
2、擴展的特點:
-編譯時決議(分類是運行時決議)?
-只以聲明的形式存在,多數情況下存在于宿主類的.m文件中(分類有聲明有實現)
-不能為系統類添加擴展(系統類可以添加分類)
代理:
是一種軟件設計模式(代理模式),并且可以添加屬性
iOS中以@protocol的形式體現
代理和通知的區別是:代理是一對一的傳遞方式,而通知是一對多的傳遞方式
delegate一般聲明為weak以規避循環引用,這樣的結果是:
代理方----strong>委托方 同時 委托方-----weak>代理方
通知:
通知是使用 觀察者模式 來實現的用于跨層傳遞消息的機制
1、問:如何實現通知機制?
在通知中心,有一個Notification_Map字典,里面存儲著以通知名稱為key,觀察者組成的數組作為value
KVO
1、什么是KVO?
-KVO是Key-value observing的縮寫
-KVO是Objective-C對觀察者設計模式的一種實現
-Apple使用了isa混寫(isa-swizzling)來實現KVO
當觀察對象的某個屬性時(當調用了addobserverforkeypath:),系統在運行時動態創建一個子類(這樣是為了重寫這個類的setter方法),并且將對象的isa指針指向新創建的這個類,修改isa的指向就是isa指針混寫的一個標志,即isa混寫技術
isa混寫技術:
指的就是將isa指針動態重新指向新的類
setter方法重寫的方法具體實現:
2、問:通過kvc設置value,kvo能否生效?
可以,原因是因為KVC改變屬性值,會進入屬性值的setter方法,從而觸發KVO
3、問:通過成員變量直接賦值value,kvo能否生效?
不可以,但是可以通過手動修改setter方法,觸發KVO
或者添加[self willChangeValueForKey:@"name"]; [self didChangeValueForKey:@"name"]; 這句話就可以了
總結:
使用setter方法改變值,KVO會生效
使用setValue:forKey:改變值,KVO會生效
成員變量直接修改需手動添加某些代碼,KVO才會生效
KVC
1、KVC是Key-value coding的縮寫。
里面有兩個重要的方法:
- (id)valueForKey:(NSString *)key;
- (void)setValue:(nullable id)value forKey:(NSString *)key;
2、問:KVC是否有違面向對象思想
KVC只要知道某個對象的私有變量名稱key,可以在外部將其value進行修改,也就是有違面向對象思想的。
valueForKey:的系統實現流程:
valueForKey:說白了就是通過一個key找到對應的value
找value可以是通過getter方法找,也可以通過直接找對應的實例變量
也就是,一個是方法,一個是實例變量,兩種方法
圖中
Accessor Method is exist?
就是通過getter方法找,有的話直接調用
Instance Var is exist?
就是有沒有對應的實例變量,有的話調用
3、:Accessor Method(訪問器方法)如何找方法呢?
通過getKey、key(正好是getter方法)、isKey三個方法,如果有則YES
這三個都是方法
4、:+(BOOL)accessInstanceVariablesDirectly的作用?
系統給我們提供了一個方法:
+(BOOL)accessInstanceVariablesDirectly,默認是返回YES
在返回YES的基礎上,才會調用Instance Var is exist,判斷是否存在相應的實例變量或者相似的實例變量
如果我們重寫該方法,使其返回NO,那么直接報沒有找到對應的值處理;不再進行實例變量的判斷。
5:Instance Var is exist?判斷規則是什么?
通過查找是否存在:_key、_isKey、key、isKey四個實例變量,如果有則YES
這四個都是實例變量
6、問:如果valueForKey:沒有找到對應的value,會怎樣?
如果valueForKey:沒有找到對應的value,會調用valueForUndefinedKey:
從而造成崩潰
YZPerson *person1 = [[YZPerson alloc] init];
NSLog(@"person1.age = %@", [person1 valueForKey:@"age"]);
7、setValue:forKey:的系統實現流程:
屬性關鍵字
1、問:屬性關鍵字可以分為哪幾類?
讀寫權限:readonly、readwrite(默認)
原子性:atomic(默認)、nonatomic
引用計數
setter\getter
atomic可以保證獲取和賦值是線程安全的
但是,并不能保證在使用過程中是線程安全的(例如對一個使用atomic修飾的數組進行添加和刪除元素并不能保證是線程安全的,只是保證在獲取數組的值和賦值時是保證線程安全的)
引用計數:
retain(非ARC)\strong(ARC中)
assign(既可以修飾基本數據類型,也可以修修飾對象類型)\unsafe_unretain(只有在MRC中使用頻繁,在ARC中基本不使用)
weak
copy
2、問:assign和weak的區別有哪些?
assign特點
可以修飾基本數據類型,如int、BOOL等
可以修飾對象類型,但不改變其引用計數器
當使用assign修飾對象,在對象釋放的時候,指針仍然反向原對象地址,會產生懸垂指針,如果繼續訪問原對象可能導致
出現內存泄露或者程序異常。
3、weak
不可以修飾基本數據類型
修飾對象類型,但不改變其引用計數器
當使用weak修飾對象,在對象釋放的時候,會自動置為nil
weak和assign的區別:assign既可以修飾基本類型,也可以修飾對象類型,weak只能修飾對象類型,第二個是assign修飾對象,在對象釋放的時候,指針仍然反向原對象地址,而weak在釋放以后被置為nil的。共同點是都不改變引用計數。
4、copy
淺拷貝
淺拷貝并沒有新建一塊內存
淺拷貝對原來的對象引用計數+1
深拷貝會新建一塊內存,與原來的內存里面內容一樣
深拷貝對原來的對象引用計數不變
深拷貝和淺拷貝的區別是否開辟了新的內存空間,是事影響了引用計數
對可變對象copy變為不可變,并且為深拷貝
對可變對象mutablecopy變為可變,深拷貝
總結:
可變對象的copy和mutableCopy均為深拷貝
不可變對象的mutableCopy是深拷貝,copy為淺拷貝。
copy返回的均是不可變對象
如果賦值過來是NSMutableArray,copy后其實是NSArray,如果對其進行添加或者刪除操作,會造成程序崩潰
5、
問:為何會做 _obj != obj 的判斷?不做可以嗎?
如果不做,則先進行[_obj release];也就是原來的對象可能已經被釋放掉了。再進行[obj retain]操作,會造成程序異常。