1、load和initialize的区别
+load和+initialize是 Objective-C runtime 会自动调用的两个类方法。但是它们被调用的时机却是有差别的,+load方法是在类被加载的时候调用的,而+initialize方法是在类或它的子类收到第一条消息之前被调用的,这里所指的消息包括实例方法和类方法的调用。也就是说+initialize方法是以懒加载的方式被调用的,如果程序一直没有给某个类或它的子类发送消息,那么这个类的+initialize方法是永远不会被调用的。此外+load方法还有一个非常重要的特性,那就是子类、父类和分类中的+load方法的实现是被区别对待的。换句话说在 Objective-C runtime 自动调用+load方法时,分类中的+load方法并不会对主类中的+load方法造成覆盖。
2、使用运行时给程序添加功能
程序增加功能,而不是完全地替换某个功能,所以我们一般都需要在自定义的实现中调用原始的实现。
#import
+ (void)load {
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
Class class = [selfclass];
SELoriginalSelector =@selector(viewWillAppear:);
SELswizzledSelector =@selector(mrc_viewWillAppear:);
MethodoriginalMethod =class_getInstanceMethod(class, originalSelector);
MethodswizzledMethod =class_getInstanceMethod(class, swizzledSelector);
BOOLsuccess =class_addMethod(class, originalSelector,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));
if(success) {
/*
主类本身有实现需要替换的方法,也就是class_addMethod方法返回NO。这种情况的处理比较简单,直接交换两个方法的实现就可以了:
*/
class_replaceMethod(class, swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));
}else{
method_exchangeImplementations(originalMethod, swizzledMethod);
/*主类本身没有实现需要替换的方法,而是继承了父类的实现,即class_addMethod方法返回YES。这时使用class_getInstanceMethod函数获取到的originalSelector指向的就是父类的方法,我们再通过执行class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));将父类的实现替换到我们自定义的mrc_viewWillAppear方法中。这样就达到了在mrc_viewWillAppear方法的实现中调用父类实现的目的。
*/
}
});
}
- (void)mrc_viewWillAppear:(BOOL)animated {
//先调用原始实现,由于主类本身有实现该方法,所以这里实际调用的是主类的实现
[selfmrc_viewWillAppear:animated];
//我们增加的功能
NSLog(@"sb王晨");
}