使用 Swift 子类化 UIApplication

Posted

技术标签:

【中文标题】使用 Swift 子类化 UIApplication【英文标题】:Subclass UIApplication with Swift 【发布时间】:2014-06-03 16:12:57 【问题描述】:

在 Objective C 中很简单:更新 main.m 文件并更改 UIApplicationMain() 参数就足够了

return UIApplicationMain(argc, argv, NSStringFromClass([CustomUIApplication class]), NSStringFromClass([AppDelegate class]));

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

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

那么,如何在 swift 中继承 UIApplication ?有什么建议吗?

【问题讨论】:

为什么最好更改UIApplicationMain() 参数,在app-info.plist 中的NSPrincipalClass 下添加类名? 【参考方案1】:

注意 XCode 10.1 和 Swift 5 的语法已于 2019 年 6 月更新(归功于 matt's answer here && Tung Fam's answer here ),如果您正在寻找以前的语法,请查看编辑部分.

好的,我找到了解决办法

首先,我注意到,在 AppDelegate.swift 文件的顶部,有这一行

@UIApplicationMain

由于这一行在任何范围之外(它在文件级别),它会立即执行,并且我假设编译器在标准主函数中翻译它。

所以,我这样做了,从一个新的 Swift-Only 应用程序开始:

注释掉了@UIApplicationMain 添加了这样的 main.swift 文件(FLApplication 是我的子类)。重要文件必须命名为 main.swift,因为其他文件不支持***语句!您不能在任何其他文件中添加 UIApplicationMain() 调用,否则您将收到此错误:

顶层不允许有表达式

这是 main.swift 文件

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

然后,使用以下代码为 UIApplication 子类 FLApplication.swift 创建一个 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 语言参考的属性部分:Link

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”的解决方案 非常酷。我很好奇现在覆盖 sendEvent: 的用例是什么(我记得在 ios 3 中必须这样做......) 如果有人想知道,UIApplicationMainmain.swift 记录在 Swift 语言参考的属性部分。 developer.apple.com/library/ios/documentation/Swift/Conceptual/… 感谢您的提示,我 99% 确定在 Swift 手册的第一个版本中没有记录 :-) 但是我会更新答案并添加您的信息。 很好的答案。在 XCode 6.3 Beta 中,您可能会发现 C_ARGCC_ARGV 已分别重命名为 Process.argcProcess.unsafeArgv。您在 main.swift 文件中的 UIApplicationMain 调用需要更新为 UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(KBApplication), NSStringFromClass(AppDelegate))【参考方案2】:

另一种方法是扩展UIApplication 而不是继承它。根据苹果发布的iBook,Swift 中的扩展可以:

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

摘自:Apple Inc.“Swift 编程语言。

如果这些功能满足了您对 UIApplication 的子类化需求,那么扩展可能是您的最佳选择。

【讨论】:

好建议 - 恕我直言:)【参考方案3】:

    创建UIApplication 的子类并添加您的逻辑

    import UIKit
    
    class CustomUIApplication: UIApplication 
        override func sendEvent(_ event: UIEvent) 
            super.sendEvent(event)
        
    
    

    创建一个调用UIApplicationMain() 全局函数[About]main.swift 文件,这是操作系统调用的应用程序的新入口点。该函数从被调用函数接收参数,UIApplication 类名,UIApplicationDelegate 类名并启动主运行循环。

    import UIKit
    
    UIApplicationMain(
        CommandLine.argc,
        CommandLine.unsafeArgv,
    
        NSStringFromClass(CustomUIApplication.self), //was created at step 1
        NSStringFromClass(AppDelegate.self)
    )
    

    删除/注释默认AppDelegate 上的@UIApplicationMain 注释。

    @UIApplicationMain 生成main.swift

    如果你不这样做,你会得到一个编译错误:

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

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

【讨论】:

以上是关于使用 Swift 子类化 UIApplication的主要内容,如果未能解决你的问题,请参考以下文章

UIViewController 的 Swift 子类化子类

使用 Swift3 子类化 CALayer + 隐式动画

子类化 NSObject 和使用泛型时 Swift 编译错误

Swift 中的 NSWindowController。使用 Nib 进行子类化和初始化

Swift 子类化 - 如何覆盖 Init()

Swift 中的自定义 UI 元素:子类化 CALayer 并覆盖 drawInContext 导致像素化绘图