处理 initialize() 的弃用【译】

在将项目迁移到 Swift 3.1 后,我受到了几个警告的欢迎。它们似乎都没有特别难以修复,只是除了这个之外:

Method ‘initialize()’ defines Objective-C class method ‘initialize’, which is not guaranteed to be invoked by Swift and will be disallowed in future versions.

Ouch。一些类重写了 NSObjectinitialize() 函数,警告清楚地表明这已不在合适(或者至少,但它应该不会很快发生)。一个非常类似的方法 - load(),它自 Swift 1.2 以来一直没有,所以看起来初始化将很快跟进。它扮演着一个独特的角色,如 NSObject 文档所述:

The runtime sends initialize() to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program.

为什么用 initialize()


如果你处于相同的情况,首先要问的问题可能是“我真的需要这个吗?”。如果你不需要的话,将逻辑移到其他地方,省去麻烦,并调用它。您通常是不需要它提供的行为的,但是自从 Swift 1.2 以后就不再支持 load()了,也没有任何明显的其他选择。在我的例子中,initialize() 被用作 method swizzling 的入口点(可能是 initialize() 的最常用的用例了)。Swizzling 允许我修补 iOS 中导致多次崩溃的错误。如果你从未听说过 method swizzling,请不要强迫自己…我只建议在特殊情况下使用它。

一个简单的解决方式


在考虑到这一点之前,load()initialize() 的一个简单替代方法是从应用程序执行你的逻辑application(_:didFinishLaunchingWithOptions:)。我建议保留相关类中包含的逻辑,并从 application delegate 中获取。从功能上讲,这个解决方案比 initialize() 更类似于 load(),但在大多数情况下,这是完全足够的。

这是相当直接的一种解决方式,在大多数情况下,为了简单起见,我建议这么做。但是,有一两个小警告。您可能有很多类要执行此操作,因此从应用程序委托中执行此操作会有点笨拙。也许您无权访问应用程序委托,或者您可能希望解决方案看起来比当前建议更具结构性。

一个不那么简单的解决方案


以下功能也比 initialize() 更接近 load()。目标是为类定义一种简单的方法来采用一个函数,并在使用该类之前调用​​该函数。虽然内部不那么简单,但它可以很好地扩展,并且是完全自包含的 - 否定了向应用程序委托添加代码的任何要求。

首先,定义以下 Swift 代码。目的是为任何您想要类似初始化行为的类提供一个简单的入口点 - 现在可以通过符合 SelfAware 协议来完成。它还提供单个函数来为每个符合要求的类启动此行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protocol SelfAware: class {
static func awake()
}

class NothingToSeeHere {

static func harmlessFunction() {

let typeCount = Int(objc_getClassList(nil, 0))
let types = UnsafeMutablePointer<AnyClass?>.allocate(capacity: typeCount)
let safeTypes = AutoreleasingUnsafeMutablePointer<AnyClass?>(types)
objc_getClassList(safeTypes, Int32(typeCount))
for index in 0 ..< typeCount { (types[index] as? SelfAware.Type)?.awake() }
types.deallocate(capacity: typeCount)

}

}

我们仍然需要一种方法来运行我们定义的函数,即 NothingToSeeHere.harmlessFunction(),在应用程序启动时。您可以从应用程序委托调用此方法,但如果您希望确保解决方案是自包含的,则以下提供了一种为 iOS 执行此操作的方法。对于没有 UIApplication 的 macOS 或其他平台,将需要以下变体。

1
2
3
4
5
6
7
8
9
10
11
12
13
extension UIApplication {

private static let runOnce: Void = {
NothingToSeeHere.harmlessFunction()
}()

override open var next: UIResponder? {
// Called before applicationDidFinishLaunching
UIApplication.runOnce
return super.next
}

}

使用此代码,符合协议 SelfAware 将授予任何类所需的行为。这样做相当容易和结构化,所以虽然这个解决方案的内部工作“不那么简单”,但我们现在有一个非常简洁的方法来向任何类添加类似初始化的行为。

原文地址


Handling the Deprecation of initialize()