方便可用的初始化程序分配自我

时间:2016-06-03 01:57:59

标签: swift

我正在尝试为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

该语法仅适用于struct和enum。

这是我唯一提出的问题

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

        self.init(string: string)
    }
}

两次构建URL。

帮助! 必须有一种我找不到的更好的方法。

更新

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

2 个答案:

答案 0 :(得分:2)

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

看着 "Failable Initializers" blog post 你可能认为你可以。 但是如果仔细观察,帖子只会显示值类型的初始化。 即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 ...
}

取决于哪一个更合适。

答案 1 :(得分:1)

您是否考虑过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
    }
  }
}