【问题标题】:Convenience Failable Initializers assign self便利的可失败初始化器分配自我
【发布时间】:2016-06-03 01:57:59
【问题描述】:

我正在尝试为 NSURL 编写一个可能会失败的初始化程序。

我非常希望它看起来像 this

extension NSURL {
    convenience init?(string: String, throwOnNil: Bool) throws {
        if let URL = NSURL(string: string) {
            self = URL
        } else if throwOnNil {
            throw MyURLError(string: string)
        } else {
            return nil
        }
    }
}

但不再支持该语法:error: cannot assign to value: 'self' is immutable

该语法仅适用于结构和枚举。

这是我唯一想到的东西

extension NSURL {
    convenience init?(string: String, throwOnNil: Bool) throws {
        if throwOnNil && NSURL(string: string) == nil {
            throw MyURLError(string: string)
        }

        self.init(string: string)
    }
}

两次构造 URL。

求助!一定有更好的方法,我没有找到。


更新

事实证明,初始化程序中的自赋值适用于结构和枚举,但不适用于类。我基于我的理想代码的示例是一个结构。

【问题讨论】:

  • 您不能像在 Objective-C 中那样在 Swift 中重新定义类的 self。当init 运行时,对象已经被分配。在init 中,您应该初始化它,而不是返回不同的对象(但为零)。此外,如果 init? 失败,这会立即传播,您无法捕获 nil 状态。如果您真的想要,Price 的建议可能是您的最佳选择。
  • @hnh Swift 1.1 允许在初始化程序中重新分配 self(请参阅:developer.apple.com/swift/blog/?id=17)。随着该功能的删除,我希望能有一个替代品。
  • @jeffery-themas 可失败的初始化程序没有被删除,并且仍然像那篇文章中描述的那样工作。我不再有 Swift 1.1 飞来飞去,但我 98% 肯定 1.1 也不允许分配 selfin class init。它总是在 enumstruct 中出现并且仍然出现(如博客条目中所示,它没有显示类 init? 的实现 - 出于某种原因?;-))。
  • @hnh 我很困惑。这篇文章显示了对Int 的扩展,它定义了init?(fromString:),它通过重新分配self 来工作。也许该链接向您展示了另一篇文章?
  • Int 不是class,而是struct - 或者换句话说:它是一个值类型。 NSURL 是一个 (@objc) 类(引用类型)。 P.S.:你可以做的另一件事是定义你自己的 struct URL 包装 NSURL。

标签: swift


【解决方案1】:

您不能像在 Objective-C 中那样在 Swift 中重新定义类(引用类型)的self。当init 运行时,对象已经被分配。在init 中,您应该初始化分配的对象,而不是返回不同的对象(但为零)。此外,如果 init? 失败,则会立即传播,您无法捕获 nil 状态。

看着 "Failable Initializers" blog post 你可能认为你可以。 但如果你仔细看,这篇文章只显示了值类型的初始化。 IE。 IntstructColorenum

我认为基本原理是在值类型中self 是实际值,而在引用类型中self 是指向未完全初始化的对象的特殊事物。

一种解决方法是使用@price-ringo 建议的工厂方法。

另一种解决方法——在这种情况下可能特别合适——是 将NSURL 包装在自己的URL 结构中。特别合适,因为一个 URL 应该是 Swift 中的值类型...示例:

struct URL {
  let url : NSURL?

  init(string: String) throws {
    if let url = NSURL(string: string) {
      self.url = url
        // or extract the values and push to struct in an even more Swifty
        // way
    }
    else {
      throw URLError()
    }
  }

  // define methods which wrap url ...
}

取决于哪个更合适。

【讨论】:

    【解决方案2】:

    您是否考虑过 NSURL 上的工厂方法?它可以帮助您完成大部分工作。

    extension NSURL {
      static func initialize(string: String, throwOnNil: Bool) throws -> NSURL? {
        if let URL = NSURL(string: string) {
          return URL
        } else if throwOnNil {
          throw MyURLError(string: string)
        } else {
          return nil
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多