一尘不染

Swift 3.1弃用了initialize()。我怎样才能做到同一件事?

swift

Objective-
C声明一个类函数initialize(),在使用每个类之前,该函数对每个类都运行一次。除其他事项外,它通常用作交换方法实现(交换)的入口。

Swift 3.1不建议使用此功能,并显示警告:

方法“ initialize()”定义了Objective-C类的方法“
initialize”,不能保证它会由Swift调用,并且在以后的版本中将不允许使用

如何解决此问题,同时仍保持与当前使用initialize()入口点实现的相同行为和功能?


阅读 394

收藏
2020-07-07

共1个答案

一尘不染

简易解决方案

常见的应用程序入口点是应用程序委托的applicationDidFinishLaunching。我们可以简单地向每个要在初始化时通知的类添加一个静态函数,然后从此处调用它。

第一个解决方案简单易懂。对于大多数情况,这是我的建议。尽管下一个解决方案提供的结果与原始initialize()功能更相似,但它也会导致应用启动时间略长。我不再认为在大多数情况下值得付出努力,降低性能或降低代码复杂性。简单的代码就是好的代码。

继续阅读以了解其他选择。您可能有理由需要它(或者可能是其中的一部分)。


没有那么简单的解决方案

第一个解决方案不一定能很好地扩展。而且,如果您要构建一个框架,而您又希望在其中运行代码而无需任何人从应用程序委托中调用它,该怎么办?

步骤1

定义以下Swift代码。目的是为您希望对其产生类似行为的任何类提供一个简单的入口点initialize()-现在可以通过遵循来简单地完成此操作SelfAware。它还提供了一个函数来为每个符合条件的类运行此行为。

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 autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
        objc_getClassList(autoreleasingTypes, Int32(typeCount))
        for index in 0 ..< typeCount { (types[index] as? SelfAware.Type)?.awake() }
        types.deallocate(capacity: typeCount)

    }

}

第二步

很好,但是我们仍然需要一种方法来实际运行我们定义的功能,即NothingToSeeHere.harmlessFunction()在应用程序启动时。以前,此答案建议使用Objective-
C代码执行此操作。但是,似乎仅使用Swift即可完成所需的工作。对于无法使用UIApplication的macOS或其他平台,将需要以下变化。

extension UIApplication {

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

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

}

第三步

现在,我们在应用程序启动时有了一个切入点,并且有一种方法可以从您选择的类中进行切入。剩下要做的就是:代替实现initialize(),遵循SelfAware和实现已定义的方法awake()

2020-07-07