Swift class 属性在由 Objective C 代码构造时未初始化

Swift class properties not initialized when constructed by Objective C code

我正在尝试在 Swift 3 中创建一个 class 来实现 Cordova 插件。我有这座建筑和 运行,但只要访问 class 的任何属性,应用程序就会崩溃。我尝试了两种初始化 class:

的方法
@objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
    var players = [UUID:DSFPlayerHandler] ();
    ...
}

@objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
    var players :[UUID:DSFPlayerHandler];
    override init () {
        players = [:];
    }
    ...
}

但是,当使用我的 players 属性 时,结果是 EXC_BAD_ACCESS 异常,地址看起来像空指针取消引用。

对象是由 Objective C 代码创建的,这是一种我完全不熟悉的语言,但我认为这是创建它的行:

obj = [[NSClassFromString(className)alloc] initWithWebViewEngine:_webViewEngine];

CDVPlugin class 包含一条评论,指出 initWithWebViewEngine 不应被覆盖(实际上我似乎 able覆盖此方法,因为虽然它在 CDVPlugin.m 文件中声明,但在 CDVPlugin.h 中未提及,因此 Swift 编译器似乎不知道它),但是相反,初始化代码应该放在一个名为 pluginInitialize 的方法中。但是,如果我这样做,我会收到编译器错误 ("Class DSFMediaCentre has no initializers").

此外,如果我将我的 init() 方法放回去并将其设置为调用 pluginInitialize(),如下所示:

override init () {
    super.init();    // necessary otherwise next line is an error
    pluginInitialize(); 
}
override func pluginInitialize() {
    players = [:];
}

然后错误变为 "Property 'self.players' not initialized at super.init call"。

如何使这个 class 正确初始化?

语言要求的严格初始化系统与您正在使用的框架使用的过程不匹配。

Swift 要求 a) 将属性初始化为对象构造的一部分,以及 b) 将构造链接到类型的超类型。但是 CDVPlugin 类型正在代表您进行构造;你没有能力定制它。 (这在 ObjC 中更有意义,因为它没有与 Swift 相同的编译时限制。)

这种情况类似于从 nib 文件中解压对象。在那种情况下,因为构建对象的是 nib 加载系统,所以您无法自定义初始化程序。您的类型将始终由 init(coder:) 构造。在某种意义上,您的初始化点进一步向下移动,到 awakeFromNib(),除此之外,这强制将存档中其他对象的出口声明为可选的,通常隐式解包。

相同的解决方案在这里应该对您有用。您应该将 pluginInitialize() 视为您的初始化点。然后该语言要求属性是可选的,因为它们不会在 its 初始化点填充。因此,使 属性 成为 IUO:

@objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
    var players :[UUID:DSFPlayerHandler]!
    override func pluginInitialize() {
        players = [:];
    }
}

一切都会好起来的。

另一个解决方案是使用 lazy 关键字

   lazy var players :[UUID:DSFPlayerHandler] = [:]

因此,您无需在初始化程序中初始化玩家,但仍要确保玩家始终不可为空