ios APP启动原理与自定义UIApplication

iOS APP启动原理

在oc项目中,入口文件是main.m文件,App启动时首先会初始化所有的类,然后再调用main.m中的main函数。

启动过程:

  1. 从类的初始化到main函数的执行
  2. 执行AppDelegate中的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

main.m代码


/*
 UIApplicationMain
 
 1 创建了 UIApplication 应用对象;
 2 创建了Application delegate(AppDelegate)对象
 3 建立了一个事件循环 (创建了runloop对象,开启事件循环)
 4 读info.plist
 
 创建一个AppDelegate的window
 UIWindowLevelAlert > UIWindowLevelStatusBar > UIWindowLevelNormal
 
*/

int main(int argc, char * argv[]) {
    @autoreleasepool {

       return  UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); // 死循环
 
    }
}

虽然main中有return,但其实没有返回任何东西,若return则代表着程序退出。主要原因在于runloop,其内部会有while循环保证程序一直运行。

第一个参数 ——argc,int类型。代表程序启动时的参数个数。默认是1

第二个参数——argv,char[]。代表各个参数的值,默认是程序的名字

第三个参数——principalClassName,NSString类型。主要传UIApplication或其子类的类名对应的字符串。如果nil,就是             UIApplication。(可以自定义UIApplication的子类,处理一些事情如:日志的统计)

第四个参数——delegateClassName,NSString类型。AppDelegate类由编译器自动生成模板。并实现里面的协议以实现我们需要的功能。由于许多配置需要在AppDelegate中进行设置,因此会造成文件代码的臃肿,可以创建APPDelegate的分类,在分类中配置一些第三方库需要的配置参数,或者广告页等,以达到瘦身的目的。

在xcode5之前,通常会写这样一段代码

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    self.window  = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    ViewController * rootVC = [ViewController new];
    self.window.rootViewController = rootVC;
    [self.window makeKeyAndVisible];
    return YES;
}

有了storyboard之后就不需要了。为什么不需要了呢?APPDelegate是如何与ViewController建立联系的。主要还是回到main函数中的UIApplicationMain这个类,在初始化的时候会加载info.plist这个资源文件,如下图所示

在资源文件中Main storyboard file base name 指定了加载Main.StoryBoard作为应用的入口文件,而Main.StoryBoard又与ViewContoller进行了关联,所以不需要做其它操作。

扫描二维码关注公众号,回复: 9889359 查看本文章

如果我们把这个配置给删除掉,那么则需要在AppDelegate的协议中写上上面那段代码。

在swift项目中其实没有main文件。而在APPDelegate.swift中多一个注解@UIApplicationMain,系统会默认将该文件作为UIApplicationMain的第四个参数。如果想要自定义,需要注释掉@UIApplicationMain,然后创建main.swift

import UIKit
import Foundation

UIApplicationMain(CommandLine.argc,
              UnsafeMutableRawPointer(CommandLine.unsafeArgv).bindMemory(to: UnsafeMutablePointer<Int8>.self, capacity: Int(CommandLine.argc)),
              nil,
              NSStringFromClass(AppDelegate.self)
)

这样就OK了。如果不使用自定义的UIApplication,那么创建main.swift文件的意义就不大。

自定义UIApplication

UIApplicationMain的第三个参数是UIApplication对象。如果传nil,则会默认调用UIApplication对象。如果我们自定义UIApplication可以提完成我们自定义的。在定义的UIApplication对象我们可以统一处理一些业务,比如日志等

import UIKit

class CustomApplication: UIApplication {

    //uiapplicton中有与Event相关的api,所以可以利用这些api完成记录行为日志的任务
    
    override func sendEvent(_ event: UIEvent) {
        //在这里处理一些统一的逻辑
        print("来自UIApplication 的 event")
        return super .sendEvent(event)
    }
    
    override func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool {
        //在这里处理一些统一的逻辑
        //例如 longinController的,某个action
        if target is ViewController && sender is UIButton && NSStringFromSelector(action) == "loginAction"{
            //记录日志或者上传服务器
            print("来自UIApplication 的 sendAction")
        }
        return super.sendAction(action, to: target, from: sender, for: event)
    }
}

在ViewController中添加一个button,并点击按钮

UIApplication的sendEvent被调用多次,然后sendAction方法被处罚,最后执行button绑定的事件

发布了47 篇原创文章 · 获赞 7 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/a1034386099/article/details/88897185
今日推荐