【问题标题】:Can you return a different instance from a Swift constructor? [duplicate]你能从 Swift 构造函数返回一个不同的实例吗? [复制]
【发布时间】:2016-11-28 21:14:42
【问题描述】:

Objective-C 有一种特殊但非常有用的能力,它可以使初始化程序返回与调用初始化程序的实例不同的实例。你可以阅读here

这对于类集群之类的东西非常有用,但即使对于确保根据特定条件返回特定实例这样简单的事情(即,使用帐号新建一个 Account 类将始终返回相同的 Account 类实例)号。)

但是,在我们的应用程序中,我们使用的是 Swift,但我没有看到这种语言中的任何此类规定。有这种事吗?

通常我们会简单地创建一个类方法来返回我们感兴趣的实例,但是虽然我们拥有所讨论的类,但我们并不拥有使用标准初始化程序语法的调用代码。例如

let foo = OurClass()

我们希望根据一些外部条件来控制将哪个实例交还给他们(为清楚起见,此处省略。)

那么 Swift 有这样的机制吗?

【问题讨论】:

  • 目前这在 Swift 中是不可能的,如果你正在寻找的话,你不能在 init 方法中创建和返回一个(子类)实例。 - 我认为这已经在swift-evolution上讨论过,但我不知道目前的状态。
  • 不,这不是我们正在做的。我们只是返回一个不同的类实例(但类型相同),因为它是针对一个 init 调用的。我在想解决方案是深入到Objective-C然后桥回到swift。会给我们想要的东西,尽管是以左三右右的方式。
  • 这是我想到的一个主题:lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/…。 - 目前你不能返回不同的实例(据我所知),子类与否。
  • 也许类级别的工厂方法比init 方法更适合这种情况。
  • 我同意,但正如我在问题中指出的那样,我们无法控制它的使用位置。我们只是试图阻止它更新和返回重复项,Apple 在我提供的链接中的文档中谈到的确切情况。

标签: swift initializer


【解决方案1】:

虽然不如 Objective-c 简单或干净,但希望您能够使用 convenience initializersfailable initializers(或两者兼有)来实现您的目标。

便捷初始化器允许您将初始化委托给另一个初始化器,实质上让您可以控制对象的初始化方式:

  class RecipeIngredient {
    var quantity: Int

    init(quantity: Int) {
        self.quantity = quantity
    }
    convenience init() {
        // You control how the properties are initialized here
        if (/* Some external or internal condition */) {
           self.init(quantity: 1)
        }
        else {
           self.init(quantity: 2)
        }
    }
 }

 // The caller
 let mysteryFood = Food()

如果条件不满足或在初始化期间发生错误,可失败初始化程序允许您在指定的初始化程序中返回 nil:

class Account {
    var id: Int

    // Failable initializers have '?' after init
    init?(id: Int) {
        // You control if the initialization succeeds or not
        if (/* check your db if id is duplicate, for example */) {
          return nil
        }
        // Succeeds
        self.quantity = quantity
    }
 }

 // The caller
 let account = Account(id: 5)
 if (account == nil) { 
   // It failed 
 }
 else { 
   // It succeeded 
 }

在您的情况下,根据您的 cmets,如果调用者尝试创建重复实例,您可能希望使用返回 nil 的 failable initializer

希望这符合您的要求!

【讨论】:

  • 我知道有失败的初始化程序,当我第一次发现它们时,我真的很兴奋......直到我意识到你唯一可以返回的是'nil'。如果他们让您返回一个新的/不同的实例,那将与 ObjC 的解决方案相提并论,并再次允许类集群和更优雅的类工厂方法,而无需显式方法(因为您只需使用初始化程序。)
  • 知道了,这很糟糕,希望 swift-evolution 提案能够通过。
  • 虽然这并不能真正回答问题,但它为可能有类似问题的人提供了有用的信息。所以,由于副本有答案,我在这里用良好的 S.O. 标记它。公民身份,没有悬而未决的问题。
【解决方案2】:

据我所知,类是不可能的,但是您可以使用结构初始化器 (self = otherValue) 来做到这一点。如果有可能,可以将类转换为可能是可行的结构。

显而易见的替代方案(并且可以说是更好的设计)是工厂方法,当使用已经存在的 API 时,您可以弃用该初始化程序或使其容易出错,以指示应改用工厂方法。否则,我会想到一些选择。

  1. 将您要返回的实例的属性复制到您正在创建的新实例中。
  2. 按照建议,下拉到 Objective-C,用于该初始化程序。
  3. 仅为 Swift 使用子类并强制使用构造函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-02
    • 2014-01-19
    • 2013-11-29
    • 2013-07-20
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多