Swift - @main 与 @UIApplicationMain

本文详细解析了iOS应用启动过程,重点讲解AppDelegate的作用,以及Objective-C与Swift中UIApplicationMain的实现与差异。通过实例演示如何自定义启动逻辑和使用子类 UIApplication。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

因为Cocoa 开发环境已经在新建一个项目时帮助我们进行了很多配置,这导致了不少刚接触iOS 的开发者都存在基础比较薄弱的问题,其中一个最显著的现象就是很多人无法说清一个App 启动的流程程序到底是怎么开始的,AppDelegate 到底是什么,xib 或者storyboard 是怎么被加载到屏幕上的? 这一系列的问题,我们在开发中虽然不会每次都会去关心和配置,但是如果能进行一些了解的话,对于程序各个部分的职责的明确会很有帮助。

在C 语言中,程序的入口都是main 函数。对于一个Objective-CiOS app 项目,在新建项目时,Xcode 将帮助我们准备好一个main.m 文件,其中就有这个main 函数

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

在这里我们调用了UIKitUIApplicationMain 方法。这个方法将根据第三个参数初始化一个UIApplication 或其子类的对象开始接收事件(在这个例子中传入nil,意味使用默认的UIApplication)。最后一个参数指定了AppDelegate 类作为应用的委托,它被用来接收类似didFinishLaunching 或者didEnterBackground 这样的与应用生命周期相关的委托方法。另外,虽然这个方法标明为返回一个int,但是其实它并不会真正返回。它会一直存在于内存中,直到用户或者系统将其强制终止。

了解了这些后,我们就可以来看看Swift 项目中对应的情况了。新建一个Swift 的iOS App 项目后,我们会发现所有文件中都没有一个像Objective-C 中那样的main 文件,也不存在main 函数唯一main 有关系的是在默认的AppDelegate 类的声明上方有一个@UIApplicationMain@main 的标签(@main 标签是通用标签,当为iOS App项目时将自动执行@UIApplicationMain 标签的内容,当为macOS 项目时,将自动执行@NSApplicationMain 标签的内容,@UIApplicationMain 标签与@NSApplicationMain 标签不互通)。

不说可能你也已经猜到,这个标签做的事情就是将被标注的类作为委托,去创建一个UIApplication启动整个程序。在编译的时候,编译器将寻找这个标记的类,并自动插入像 main 函数这样的模板代码。我们可以试试把@UIApplicationMain 去掉会怎么样:

Entry point (_main) undefined. for architecture x86_64

这说明找不到main 函数了。

在一般情况下,我们并不需要对这个标签做任何修改,但是当我们想使用UIApplication 的子类而不是它本身的话,我们就需要对这部分内容做点“手脚”了。

刚才说到,其实Swift 的App 也是需要main 函数的,只不过默认情况下是@UIApplicationMain 帮助我们自动生成了而已。和C 语言的main.c 或者main.m 文件一样,Swift 项目也可以有一个名为main.swift 的特殊文件。在这个文件中,我们不需要定义作用域,而可以直接书写代码。这个文件中的代码将作为main 函数来执行。比如我们在删除@UIApplicationMain 后,在项目中添加一个main.swift 文件,然后加上这样的代码:

import Foundation
import UIKit

UIApplicationMain(CommandLine.argc, UnsafeMutablePointer(CommandLine.unsafeArgv), NSStringFromClass(UIApplication.self), NSStringFromClass(AppDelegate.self))

现在编译运行后,就不会再出现错误了。当然,我们还可以将第三个参数替换成自己的UIApplication 子类,这样我们就可以轻易的做一些控制整个应用行为的事情了,比如将main.swift 的内容换成:

class MyApplication: UIApplication {
    override func sendEvent(_ event: UIEvent) {
        super.sendEvent(event)
        print("Event sent: \(event)")
    }
}
UIApplicationMain(CommandLine.argc, UnsafeMutablePointer(CommandLine.unsafeArgv), NSStringFromClass(MyApplication.self), NSStringFromClass(AppDelegate.self))

这样每次发送事件(比如点击按钮)时,我们都可以监听到这个事件了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值