runtime 使用总结
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor grayColor]; for(NSString *familyName in [UIFont familyNames]){ NSLog(@"Font FamilyName = %@",familyName); //输出字体族科名字 for(NSString *fontName in [UIFont fontNamesForFamilyName:familyName]) { NSLog(@"------\t%@",fontName); //输出字体族科下字样名字 } } _myLabel.font = [UIFont fontWithName:@"Copperplate-Bold" size:17.0f]; _myButton.titleLabel.font = [UIFont fontWithName:@"Heiti SC" size:17.0f]; }
//设置系统字体
苹果默认 Heiti SC 黑体
+load 总结
1 当APP程序启动,就会循环调用每个类的+load方法 (不管这个类是否被调用)
2 直接使用函数内存地址的方式 (*load_method)(cls, SEL_load); 对 +load 方法进行调用的,而不是使用发送消息 objc_msgSend 的方式。
3 父类(子类)的+load是分开调用的,类(分类)+load方法是分开调用的 (就是说不存在使用子类调用父类+load方法)
4 优先级 父类+load方法优先于子类+load方法 ; 类+load方法优先于分类的+load方法
+load 补充:
1 app项目安装到手机是 以二进制(Match-o)的形式 存储在硬盘中
2 当点击app图标启动的一刻,将硬盘的二进制 加载进内存,这个过程叫做装载
3 此时在二进制存放进内存,cpu会等等待load先调用,load 调用时候,对象还没有创建
+initialize 总结
1 调用时间: 当父类,子类 接受到第一条消息(类方法/对象方法)之前调用,且仅仅调用一次.
2 实现机制:属于懒加载,没用到不调用 objc_msgSend 的发消息。
3 和+load不同 当前类被调用时候,调用+initialize,会触发父类的+initialize 调用(就是调用两遍当前类/父类各一次,优先级,先调用父类,然后子类)
4 分类实现+initialize 会覆盖本类额+initialize方法 只调用一次.
总结
+load | +initialize | |
---|---|---|
调用时机 | 被添加到 runtime 时 | 到第一条消息前,可能永远不调用 |
同一个类,调用次数 (不考虑主动调用) |
1次 | 1次 |
调用顺序 | 父类->本类->分类 | 父类->本类(如果有分类,则调用分类) |
若自身未实现,是否沿用父类的方法? | 否 | 是 |
类别中的定义 | 全都执行,但后于本类的方法 | 覆盖本类的方法,只执行一个 |
线程安全 | 安全 | 安全 |
正题: runtime 修改系统字体
systemFontOfSize:
,覆盖它的原有方法实现,但是这样做就无法调用系统原有的方法,而且苹果也不建议在category中重写方法:利用runtime另写一个方法来和systemFontOfSize:
交换
-
Method Swizzling
主要通过以下面的方法来交换method_exchangeImplementations(originalMethod, swizzledMethod);
这尼玛就是下钩子
sel(方法编号)----imp(方法实现) 一一对应的关系
注意 sel--imp 非指针指向地址,imp才是指向函数(方法实现函数)的指针
imp通过指针找到实现地址,找到二进制代码块
交换 sel和imp的对应关系
+ (void)load{ //只执行一次这个方法 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class class = [self class]; SEL originalSelector = @selector(systemFontOfSize:); SEL swizzledSelector = @selector(mysystemFontOfSize:); // Class class = class_getInstanceMethod((id)self); Method originalMethod = class_getClassMethod(class, originalSelector); Method swizzledMethod = class_getClassMethod(class, swizzledSelector); BOOL didAddMethod = class_addMethod(class,originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (didAddMethod) { class_replaceMethod(class,swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } }); }
相关地址:
https://www.jianshu.com/p/4bf2b22b9986
https://www.jianshu.com/p/8836dfac7f2c