使用Swift子类化UIApplication

92
在 Objective C 中,只需要更新 main.m 文件并更改 UIApplicationMain() 参数就足够了。
return UIApplicationMain(argc, argv, NSStringFromClass([CustomUIApplication class]), NSStringFromClass([AppDelegate class]));

但是在Swift中没有main.m文件,因为该指南说:

“在全局范围编写的代码用作程序的入口点,因此您不需要main函数。”

那么,如何在Swift中创建子类化UIApplication?有什么建议吗?


1
为什么将UIApplicationMain()参数更改为在app-info.plist下添加类名到NSPrincipalClass会更可取? - Andreas
3个回答

174
请注意,2019年6月(感谢matt's answer hereTung Fam's answer here),XCode 10.1和Swift 5的语法已更新。如果您正在寻找以前的语法,请查看编辑部分。
好的,我找到了解决方案。
首先,我注意到在AppDelegate.swift文件的顶部有这行代码。
@UIApplicationMain

由于此行位于任何范围之外(它在文件级别),因此会立即执行,我假设编译器将其转换为标准的main函数。

因此,我从一个新的仅Swift应用程序开始:

  • 注释掉@UIApplicationMain
  • 添加一个像这样的main.swift文件(FLApplication是我的子类)。
    重要提示文件必须命名为main.swift,因为其他文件不支持顶级语句!否则,您将收到此错误:

不允许在顶层使用表达式

这是main.swift文件

UIApplicationMain(
    CommandLine.argc, CommandLine.unsafeArgv, 
    NSStringFromClass(FLApplication.self), NSStringFromClass(AppDelegate.self)
)

然后,创建一个名为FLApplication.swift的UIApplication子类的Swift文件,并使用以下代码:
import UIKit
import Foundation

class FLApplication: UIApplication {
    override func sendEvent(_ event: UIEvent) {
        super.sendEvent(event)
        print("send event")
    }
}

现在,UIApplication已经正确地被子类化,您将在日志中看到“发送事件”消息。


旧版本修改记录
为了方便参考,由于从第1版到第3版发生了很大变化,我在此保留所有的旧版本编辑记录。


编辑 - 2015年3月

如胡军峰所评论的,现在关于UIApplicationMain和main.swift文件的解释已经记录在《Swift语言参考》的属性部分中:链接

如Thomas Verbeek所评论的,在XCode 6.3 Beta中,你可能会发现C_ARGC和C_ARGV已被重命名为Process.argc和Process.unsafeArgv。因此,你需要更新main.swift文件中的UIApplicationMain调用:

UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(FLApplication), NSStringFromClass(AppDelegate))

在XCode 8之前的语法是

import Foundation
import UIKit

UIApplicationMain(C_ARGC, C_ARGV, NSStringFromClass(FLApplication), NSStringFromClass(AppDelegate))

编辑 - 2016年12月

Xcode 8的解决方案,在beta 6之前

import Foundation
import UIKit

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

我正在尝试理解是否可以直接在AppDelegate.swift文件中调用UIApplicationMain(),因为似乎有一个这个方法的“swift版本”,但我遇到了编译器错误,我将进行一些测试以寻找“仅限swift”的解决方案。 - LombaX
2
如果有人想知道,UIApplicationMainmain.swift在Swift语言参考手册的属性部分有详细说明。https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html - Junfeng
5
好的,我会尽力进行翻译。在XCode 6.3 Beta版本中,你可能会发现 C_ARGCC_ARGV 已经被分别重命名为 Process.argcProcess.unsafeArgv。因此,你需要更新 main.swift 文件中的 UIApplicationMain 调用,改为 UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(KBApplication), NSStringFromClass(AppDelegate)) - Thomas Verbeek
@LombaX 在 main.swift 中,UIApplicationMain() 返回一个 Int32。因此,难道不应该将其包装在 exit() 调用中,以便进程可以向操作系统报告其退出状态吗?就像 exit(UIApplicationMain(...)) 一样。 - Eric Baker
@LombaX 不用理会我之前关于使用 exit() 的评论。UIApplicationMain() 的文档中说:“该函数永远不会返回。当用户退出 iOS 应用程序时...应用程序将移动到后台。”因此,似乎 iOS 正在“包装”启动的 iOS 应用程序进程,并忽略进程本来会终止的任何退出代码。 - Eric Baker
显示剩余6条评论

4
一个替代方案是扩展UIApplication而不是对其进行子类化。根据苹果发布的iBook,Swift中的扩展可以:

添加计算属性和计算静态属性 定义实例方法和类型方法 提供新的初始化程序 定义下标 定义和使用新的嵌套类型 使现有类型符合协议

摘自:Apple Inc. “The Swift Programming Language.

如果您在对UIApplication进行子类化的需求已经满足了这些功能,则扩展可能是一个好的选择。

5
好的建议 - 在我看来不是答案 :) - Daij-Djan

1

Swift子类UIApplication

  1. 创建一个UIApplication的子类,并添加你的逻辑

    import UIKit
    
    class CustomUIApplication: UIApplication {
        override func sendEvent(_ event: UIEvent) {
            super.sendEvent(event)
        }
    }
    
  2. 创建一个main.swift文件,调用UIApplicationMain()全局函数[关于],这是你的应用程序的新入口点,由操作系统调用。该函数接收来自被调用函数的参数,包括UIApplication类名、UIApplicationDelegate类名,并启动主运行循环[关于]

    import UIKit
    
    UIApplicationMain(
        CommandLine.argc,
        CommandLine.unsafeArgv,
    
        NSStringFromClass(CustomUIApplication.self), //在步骤1中创建
        NSStringFromClass(AppDelegate.self)
    )
    
  3. 删除/注释默认的AppDelegate上的@UIApplicationMain注解。

@UIApplicationMain 会生成 main.swift 文件。

如果你不这样做,将会出现编译错误:

UIApplicationMain 属性不能在包含顶级代码的模块中使用。

//@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    //...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接