在Swift中,为什么我需要覆盖这个初始化程序才能使我自己的方便初始化程序?

时间:2014-11-03 14:48:49

标签: ios swift initialization override uistoryboard

我有这堂课:

class MyStoryboard: UIStoryboard {
   override init() {
        super.init(name: "SomeName", bundle: nil);
    }
}

Swift不接受这个,因为我没有调用指定的初始化程序。但是UIStoryBoard的标题有

@availability(iOS, introduced=5.0)
class UIStoryboard : NSObject {
    init(name: String, bundle storyboardBundleOrNil: NSBundle?) -> UIStoryboard

    func instantiateInitialViewController() -> AnyObject
    func instantiateViewControllerWithIdentifier(identifier: String) -> AnyObject!
}

此处没有convenience个关键字。但是说它是一个方便的初始化器。然后这应该工作:

class CharacterStoryboard: UIStoryboard {        
    convenience override init() {
        self.init(name: "SomeName", bundle: nil);
    }
}

但是这会给出错误"额外的参数' name'在电话"中,好像这个初始化器甚至不存在。

我发现的唯一工作就是这样做:

class CharacterStoryboard: UIStoryboard {
    convenience init(name: String, bundle storyboardBundleOrNil: NSBundle?) {
        self.init(name: name, bundle: storyboardBundleOrNil)
    }

    convenience override init() {
        self.init(name: "SomeName", bundle: nil);
    }
}

这只是Swift中的一个错误,还是我错过了一些重要的东西?

更新

这段代码在运行时会创建一个无限循环,正如我之前应该发现的那样。

我认为这绝对是一个Swift错误,我应该放弃它。

1 个答案:

答案 0 :(得分:1)

是的,这几乎肯定是一个错误。 Filing it with Apple is probably a good idea

一些ObjC API有一个奇怪的例子,它只将工厂方法导入Swift作为“排序”初始化器;您可以看到UIStoryboard的情况,因为init(...)签名具有返回类型:

init(name: String, bundle storyboardBundleOrNil: NSBundle?) -> UIStoryboard
                                                            ^^^^^^^^^^^^^^^

您不能在自己的Swift代码中声明带有返回类型的init - 这只是ObjC-to-Swift导入器的工件。当你有一个像这样导入的类时,你会陷入无法编写调用指定初始值设定项的子类init的情况下(因为就Swift知道没有指定的初始化程序而言)而你无法调用工厂方法。所以,是的,sounds like a bug

请注意,即使修复此问题,您仍可能需要覆盖init(name:bundle:)才能从自己的convenience init()调用它。我希望这个类的正确Swift API有failable initializer(因为你可以指定磁盘上不存在的名称或包)。如果您要根据可用的init()实施未失败的init?(...),则必须通过init!(...)as seen in this answer委派两次。