每天记一下,日积月累,总会有进步。
以下内容都是摘自各个大牛博客
2017-03-10:
objc_msgSend
做了什么?
举个🌰
objc_msgSend(obj, foo)
是如何执行的:
- 首先通过 objc 的 isa 指针找到它的 class ;
- 再在 class 的 method list 找到 foo ;
- 如果 class 中没有找到 foo ,继续往它的 superclass 中去找;
- 只要找到 foo 这个函数, 就会去执行它的 IMP.
其实也并不是每次执行 foo 都会去这样遍历
objc_method_list
,这样也并合理。那又是怎么做的呢?那就是objc_class
中的另一个重要成员objc_cache
。它会把调用过的函数缓存下来。在找到 foo 之后,把 foo 的method_name
作为 key ,method_imp
作为 value 存起来了。当再次收到 foo 消息时,就可以直接在 cache 里面找到,避免去遍历objc_method_list
,从而大大的提高函数查询的效率。
Objective-C 中给一个对象发送消息会经过以下几个步骤:
- 在对象类的 dispatch table 中尝试找到该消息。如果找到了,跳到相应的函数IMP中执行代码;
- 如果没找到,Runtime 会发送
+resolveInstanceMethod:
(实例方法) 或者resolveClassMethod:
(类方法) 尝试去 resolve (解决) 这个消息;- 如果 resolve 方法返回NO,Runtime 就会发送
-forwardingTargetForSelector:
允许你把这个消息转发给另外一个对象;- 如果没新的目标对象返回,Runtime 就会发送
-methodSignatureForSelector:
和-forwardInvocation:
消息。你可以发送-invokeWithTarget:
消息来手动转发消息或者发送-doesNotRecognizeSelector:
抛出异常。
2017-03-24:
对于OC中的类来说,在runtime中会有两个方法被调用:
+load
+initialize
这两个方法看起来都是在类初始的时候调用的,但其实还是有一些异同,从而可以用来做一些行为。
+load
首先,load方法是一定会在runtime中被调用的,只要类被添加到runtime中了,就会调用load方法,所以我们可以自己实现laod方法来在这个时候执行一些行为。
而且有意思的一点是,load方法不会覆盖。也就是说,如果子类实现了load方法,那么会先调用父类的load方法,然后又去执行子类的load方法。同样的,如果分类实现了load方法,也会先执行主类的load方法,然后又会去执行分类的load方法。所以父类的load会执行很多次,这一点需要注意。而且执行顺序是 类 -> 子类 ->分类。而不同类之间的顺序不一定。
+initialize
与load不同的是,initialize方法不一定会执行。只有当一个类第一次被发送消息的时候会执行,注意是第一次。什么叫发送消息呢,就是执行类的一些方法的时候。也就是说这个方法是懒加载,没有用到这个类就不会调用,可以节省系统资源。
还有一点截然相反,却更符合我们预期的就是,initialize方法会覆盖。也就是说如果子类实现了initialize方法,就不会执行父类的了,直接执行子类本身的。如果分类实现了initialize方法,也不会再执行主类的。所以initialize方法的执行覆盖顺序是 分类 -> 子类 ->类。且只会有一个initialize方法被执行。
2017-03-15:
一个拓展,获取任意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的?
因为当我们将控件拖到Storyboard上,相当于新创建了一个对象,而这个对象是加到视图控制器的view上,view有一个subViews属性,这个属性是一个数组,里面是这个view的所有子view,而我们加的控件就位于这个数组中,那么说明,实际上我们的控件对象是属于view的,也就是说view对加到它上面的控件是强引用。当我们使用Outlet属性的时候,我们是在viewController里面使用,而这个Outlet属性是有view来进行强引用的,我们在viewController里面仅仅是对其使用,并没有必要拥有它,所以是weak的
2017-07-06
weakSelf和strongSelf
weakSelf 是为了block不持有self,避免Retain Circle循环引用。在 Block 内如果需要访问 self 的方法、变量,建议使用 weakSelf。
strongSelf的目的是因为一旦进入block执行,假设不允许self在这个执行过程中释放,就需要加入strongSelf。block执行完后这个strongSelf 会自动释放,没有不会存在循环引用问题。如果在 Block 内需要多次 访问 self,则需要使用 strongSelf
2017-07-31
block的生命周期?
block
是一个对象,它的生命周期很简单,只要看持有block
的对象是不是也被block
持有。如果没有持有,就不用担心循环引用的问题。
如何解决blcok产生的循环引用?
可以用
__weak(ARC)
或__block(MRC)
来解决。
block对于参数形式传进来的对象,会不会强引用?
其实
block
与函数一样,对于传进来的参数,并不会持有。