每天記一下,日積月累,總會(huì)有進(jìn)步。
以下內(nèi)容都是摘自各個(gè)大牛博客
2017-03-10:
objc_msgSend做了什么?
舉個(gè)??
objc_msgSend(obj, foo)是如何執(zhí)行的:
- 首先通過 objc 的 isa 指針找到它的 class ;
- 再在 class 的 method list 找到 foo ;
- 如果 class 中沒有找到 foo ,繼續(xù)往它的 superclass 中去找;
- 只要找到 foo 這個(gè)函數(shù), 就會(huì)去執(zhí)行它的 IMP.
其實(shí)也并不是每次執(zhí)行 foo 都會(huì)去這樣遍歷
objc_method_list,這樣也并合理。那又是怎么做的呢?那就是objc_class中的另一個(gè)重要成員objc_cache。它會(huì)把調(diào)用過的函數(shù)緩存下來。在找到 foo 之后,把 foo 的method_name作為 key ,method_imp作為 value 存起來了。當(dāng)再次收到 foo 消息時(shí),就可以直接在 cache 里面找到,避免去遍歷objc_method_list,從而大大的提高函數(shù)查詢的效率。
Objective-C 中給一個(gè)對(duì)象發(fā)送消息會(huì)經(jīng)過以下幾個(gè)步驟:
- 在對(duì)象類的 dispatch table 中嘗試找到該消息。如果找到了,跳到相應(yīng)的函數(shù)IMP中執(zhí)行代碼;
- 如果沒找到,Runtime 會(huì)發(fā)送
+resolveInstanceMethod:(實(shí)例方法) 或者resolveClassMethod:(類方法) 嘗試去 resolve (解決) 這個(gè)消息;- 如果 resolve 方法返回NO,Runtime 就會(huì)發(fā)送
-forwardingTargetForSelector:允許你把這個(gè)消息轉(zhuǎn)發(fā)給另外一個(gè)對(duì)象;- 如果沒新的目標(biāo)對(duì)象返回,Runtime 就會(huì)發(fā)送
-methodSignatureForSelector:和-forwardInvocation:消息。你可以發(fā)送-invokeWithTarget:消息來手動(dòng)轉(zhuǎn)發(fā)消息或者發(fā)送-doesNotRecognizeSelector:拋出異常。
2017-03-24:
對(duì)于OC中的類來說,在runtime中會(huì)有兩個(gè)方法被調(diào)用:
+load
+initialize
這兩個(gè)方法看起來都是在類初始的時(shí)候調(diào)用的,但其實(shí)還是有一些異同,從而可以用來做一些行為。
+load
首先,load方法是一定會(huì)在runtime中被調(diào)用的,只要類被添加到runtime中了,就會(huì)調(diào)用load方法,所以我們可以自己實(shí)現(xiàn)laod方法來在這個(gè)時(shí)候執(zhí)行一些行為。
而且有意思的一點(diǎn)是,load方法不會(huì)覆蓋。也就是說,如果子類實(shí)現(xiàn)了load方法,那么會(huì)先調(diào)用父類的load方法,然后又去執(zhí)行子類的load方法。同樣的,如果分類實(shí)現(xiàn)了load方法,也會(huì)先執(zhí)行主類的load方法,然后又會(huì)去執(zhí)行分類的load方法。所以父類的load會(huì)執(zhí)行很多次,這一點(diǎn)需要注意。而且執(zhí)行順序是 類 -> 子類 ->分類。而不同類之間的順序不一定。
+initialize
與load不同的是,initialize方法不一定會(huì)執(zhí)行。只有當(dāng)一個(gè)類第一次被發(fā)送消息的時(shí)候會(huì)執(zhí)行,注意是第一次。什么叫發(fā)送消息呢,就是執(zhí)行類的一些方法的時(shí)候。也就是說這個(gè)方法是懶加載,沒有用到這個(gè)類就不會(huì)調(diào)用,可以節(jié)省系統(tǒng)資源。
還有一點(diǎn)截然相反,卻更符合我們預(yù)期的就是,initialize方法會(huì)覆蓋。也就是說如果子類實(shí)現(xiàn)了initialize方法,就不會(huì)執(zhí)行父類的了,直接執(zhí)行子類本身的。如果分類實(shí)現(xiàn)了initialize方法,也不會(huì)再執(zhí)行主類的。所以initialize方法的執(zhí)行覆蓋順序是 分類 -> 子類 ->類。且只會(huì)有一個(gè)initialize方法被執(zhí)行。
2017-03-15:
一個(gè)拓展,獲取任意ViewController的navigationController
@implementation UIViewController (IMYPublic)
- (UINavigationController*)imy_navigationController {
UINavigationController* nav = nil;
if ([self isKindOfClass:[UINavigationController class]]) {
nav = (id)self;
}
else {
if ([self isKindOfClass:[UITabBarController class]]) {
nav = [((UITabBarController*)self).selectedViewController imy_navigationController];
}
else {
nav = self.navigationController;
}
}
return nav;
}
@end
2017-07-04
為什么IBOutlet屬性是weak的?
因?yàn)楫?dāng)我們將控件拖到Storyboard上,相當(dāng)于新創(chuàng)建了一個(gè)對(duì)象,而這個(gè)對(duì)象是加到視圖控制器的view上,view有一個(gè)subViews屬性,這個(gè)屬性是一個(gè)數(shù)組,里面是這個(gè)view的所有子view,而我們加的控件就位于這個(gè)數(shù)組中,那么說明,實(shí)際上我們的控件對(duì)象是屬于view的,也就是說view對(duì)加到它上面的控件是強(qiáng)引用。當(dāng)我們使用Outlet屬性的時(shí)候,我們是在viewController里面使用,而這個(gè)Outlet屬性是有view來進(jìn)行強(qiáng)引用的,我們?cè)趘iewController里面僅僅是對(duì)其使用,并沒有必要擁有它,所以是weak的
2017-07-06
weakSelf和strongSelf
weakSelf 是為了block不持有self,避免Retain Circle循環(huán)引用。在 Block 內(nèi)如果需要訪問 self 的方法、變量,建議使用 weakSelf。
strongSelf的目的是因?yàn)橐坏┻M(jìn)入block執(zhí)行,假設(shè)不允許self在這個(gè)執(zhí)行過程中釋放,就需要加入strongSelf。block執(zhí)行完后這個(gè)strongSelf 會(huì)自動(dòng)釋放,沒有不會(huì)存在循環(huán)引用問題。如果在 Block 內(nèi)需要多次 訪問 self,則需要使用 strongSelf
摘自深入研究Block用weakSelf、strongSelf、@weakify、@strongify解決循環(huán)引用
2017-07-31
block的生命周期?
block是一個(gè)對(duì)象,它的生命周期很簡(jiǎn)單,只要看持有block的對(duì)象是不是也被block持有。如果沒有持有,就不用擔(dān)心循環(huán)引用的問題。
如何解決blcok產(chǎn)生的循環(huán)引用?
可以用
__weak(ARC)或__block(MRC)來解決。
block對(duì)于參數(shù)形式傳進(jìn)來的對(duì)象,會(huì)不會(huì)強(qiáng)引用?
其實(shí)
block與函數(shù)一樣,對(duì)于傳進(jìn)來的參數(shù),并不會(huì)持有。