【问题标题】:In Swift, how do I create a convenience init for a class where the init's implementation creates the class value instead of calling an existing init在 Swift 中,我如何为一个类创建一个方便的 init,其中 init 的实现创建类值而不是调用现有的 init
【发布时间】:2016-02-11 06:37:07
【问题描述】:

我觉得答案很明显,但我无法弄清楚,这对我来说似乎是一个反复出现的问题。基本上我想做这样的事情:

extension NSData {
    convenience init(JSONObject: AnyObject) {
        do {
            self = try NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
        }
        catch {
            self = nil
        }
    }
}

但是它不会让我简单地为 self 赋值。我一直用枚举来做这件事,但它不会让我用类来做。有没有办法使用在初始化器实现中创建的类的实例来实现便利初始化器?

【问题讨论】:

  • 我的理解是 self 是不可变的,并且便利的 inits 必须使用指定的 inits 才能使它们工作,您是在初始创建实例中创建第二个实例,所以这将不起作用。相反,您将不得不创建一个仅返回新实例的扩展方法
  • 好的,感谢您的确认。我想我最终只能使用静态方法而不是 init。

标签: swift


【解决方案1】:

说工厂初始化器在 Swift 中“尚不支持是错误的。它们的排除是一个设计决定,它们的使用旨在由可失败的初始化程序覆盖;引用the following Apple Swift blog post

可失败初始化程序消除了工厂的最常见原因 Swift 中的方法,这是以前报告失败的唯一方法 在构造这个对象时。

...

使用可失败初始化器允许更多地使用 Swift 的统一 构造语法,通过消除简化语言 初始化器和工厂之间的混淆和重复 方法

因此,在您的情况下,您可能正在寻找一个方便的可失败初始化程序。例如,类似的东西

extension NSData {
    convenience init?(JSONObject: AnyObject) {
        do {
            let foo = try NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
            self.init(data: foo)
        }
        catch {
            return nil
        }
    }
}

/* Example usage */
let foo : AnyObject = ["Foo":"bar"]
let bar = NSData.init(JSONObject: foo)

在您的问题标题中包含 "... 而不是调用现有的 init"。当使用convenience 初始化器时,必须在某个时候调用指定的初始化器(同一个类)(甚至通过其他便利初始化器)。来自Swift Language Guide - Initialization - Class Inheritance and Initialization

...

规则 2

便利构造器必须从同一个构造器调用另一个构造器 类。

规则 3

便利构造器最终必须调用指定的 初始化器。

然而,如果NSJSONSerialization.dataWithJSONObject(...) 失败,上面的示例代码允许便利初始化程序的早期转义(失败),但如果成功,迟早需要调用指定的初始化程序(在这种情况下init(data:) 指定初始化器)。


有关可失败初始化程序的详细信息,请参阅Swift Language Guide - Initialization - Failable Initializers。有关初始化链 (convenience -> ... -> designated initializer) 的附加说明,请参阅下面的 rickster:s 评论。

【讨论】:

  • 你遗漏了初始化俱乐部的规则 1:不要谈论初始化俱乐部。呃,等等。真的,给一篇好文章补充一点:所有这些链接业务都是 Swift 中初始化模型的关键,因为它确保没有实例在没有处理所有状态的情况下“逃脱”初始化,并且没有一次性实例在初始化期间创建/丢弃(当您将 +objectWithXYZ 工厂包装在 ObjC 中的 -initWithPDQ 初始化程序中时会发生这种情况)。
  • @rickster 感谢您的反馈和额外的初始化俱乐部见解。
  • 这回答了我的问题。基本上我想知道你是否可以像使用结构、枚举和其他值类型一样通过分配 self 来初始化一个类。看起来你不能。原因是有道理的。我只是希望每个类都有一个内置的复制构造函数,这样您就可以通过将由其他库创建的类的实例提供给复制构造函数来实现便利初始化程序。这将满足初始化链接规则,同时在您如何实现便利初始化方面具有灵活性。看上面的例子,NSData 有一个拷贝构造函数(init),但是大多数类没有
【解决方案2】:

如果我理解正确,您需要一个工厂初始化程序。在 Swift 中,它们尚不受支持。你能做的最好的就是使用静态工厂方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-19
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 2017-03-24
    • 2012-08-15
    • 1970-01-01
    相关资源
    最近更新 更多