使用rumtime匹配不同屏幕字体大小,顺便聊聊启动那些事
先来看效果图,为了区分效果把label的位置设的小一些
5s:

6s Plus:

6s Plus 明显不能全部展示
实现方式也很简单,给UIFont添加类目(分类),利用runtime在+load中替换原有的systemFontOfSize:方法,用现手机的屏幕宽度 / 最小的屏幕宽度 * 字体大小 , 从而实现不同屏幕适配字体大小
.m
+ (void)load{
//获取替换后的类方法
Method newMethod = class_getClassMethod([self class], @selector(adaptiveFont:));
//获取替换前的类方法
Method method = class_getClassMethod([self class], @selector(systemFontOfSize:));
//然后交换类方法
method_exchangeImplementations(newMethod, method);
}
// 自适应大小
+ (UIFont *)adaptiveFont:(CGFloat)fontSize{
UIFont *newFont ;
// 手机宽度 / 最小宽度 * 字体大小 达到适配的目的
newFont = [UIFont adaptiveFont:fontSize * [UIScreen mainScreen].bounds.size.width/minimumWidth];
return newFont;
}
使用的话正常 systemFontOfSize: 就好,加粗的也同理
下面我们深入了解下

在main.m 中

打印结果:

可以看出+load 先执行了
load 可以说我们在日常开发中可以接触到的调用时间最靠前的方法,在主函数运行之前,load 方法就会调用。
由于它的调用不是惰性的,且其只会在程序调用期间调用一次,最最重要的是,如果在类与分类中都实现了 load 方法,它们都会被调用,不像其它的在分类中实现的方法会被覆盖
顺便也讲讲main.m

UIApplication 的代理方法
// 当应用程序启动完毕的时候就会调用(系统自动调用)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(@"didFinishLaunchingWithOptions");
return YES;
}
// 即将失去活动状态的时候调用(失去焦点, 不可交互)
// 当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件,比如来电话了
- (void)applicationWillResignActive:(UIApplication *)application
{
NSLog(@"ResignActive");
}
// 重新获取焦点(能够和用户交互)
// 应用程序进入活动状态执行
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(@"BecomeActive");
}
// 应用程序进入后台的时候调用
// 一般在该方法中保存应用程序的数据,关闭网络连接等
// 系统默认 时间5秒,超时会被终止
//如果不够可以用beginBackgroundTaskWithExpirationHandler:来延长
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(@"Background");
}
// 应用程序即将进入前台的时候调用
// 一般在该方法中恢复applicationDidEnterBackground销毁的内容
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSLog(@"Foreground");
}
// 应用程序即将被销毁的时候会调用该方法
// 注意:如果应用程序处于挂起状态的时候无法调用该方法
- (void)applicationWillTerminate:(UIApplication *)application
{
}
// 应用程序接收到内存警告的时候就会调用
// 一般在该方法中释放掉不需要的内存
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
// 1. 停止所有下载
[[SDWebImageManager sharedManager] cancelAll];
// 2. 清除缓存
[[SDWebImageManager sharedManager].imageCache clearMemory];
NSLog(@"MemoryWarning");
}
程序启动的完整过程
1.main函数
2.UIApplicationMain
-
创建UIApplication对象
-
创建UIApplication的delegate对象
3.delegate对象开始处理(监听)系统事件(没有storyboard)
-
程序启动完毕的时候, 就会调用代理的application:didFinishLaunchingWithOptions:方法
-
在application:didFinishLaunchingWithOptions:中创建UIWindow
-
创建和设置UIWindow的rootViewController
-
显示窗口
3.根据Info.plist获得最主要storyboard的文件名,加载最主要的storyboard(有storyboard)
-
创建UIWindow
-
创建和设置UIWindow的rootViewController
-
显示窗口
参考链接
http://www.cnblogs.com/wendingding/p/3766347.html
http://www.cocoachina.com/ios/20160516/16273.html