使用 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 中必须这样做......)
如果有人想知道,UIApplicationMain
和 main.swift
记录在 Swift 语言参考的属性部分。 developer.apple.com/library/ios/documentation/Swift/Conceptual/…
感谢您的提示,我 99% 确定在 Swift 手册的第一个版本中没有记录 :-) 但是我会更新答案并添加您的信息。
很好的答案。在 XCode 6.3 Beta 中,您可能会发现 C_ARGC
和 C_ARGV
已分别重命名为 Process.argc
和 Process.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 子类化子类
子类化 NSObject 和使用泛型时 Swift 编译错误