如何保护可能失败的属性的初始化

时间:2016-01-15 05:59:00

标签: swift optional

我的类有一个类型NSURL的属性,它是从字符串初始化的。该字符串在编译时已知。

要使类正常运行,必须在初始化(不迟到)时设置为其预期值,因此没有指出将其定义为可选(隐式展开或以其他方式):

class TestClass: NSObject {

    private let myURL:NSURL

    ...

假设NSURL(string:)(返回NSURL?)如果传递了编译时已知的有效URL字符串,则永远不会失败,我可以这样做:

    override init() {

        myURL = NSURL(string: "http://www.google.com")!

        super.init()
    }

然而,我不知何故在强制解包时感到不舒服并且想以某种方式保护URL初始化。如果我试试这个:

    guard myURL = NSURL(string: "http://www.google.com") else {
        fatalError()
    }
  

可选类型'NSURL?'的值没有打开;你的意思是用'!'   还是'?'?

(注意:无法在上方代码的任何位置添加!?来解决错误。有条件的解包只会在guard let... guard var...时发生,并且myURL已定义)

我理解为什么会失败:即使成功调用NSURL(string:),也会将(有效)NSURL 包裹返回到可选NSURL?内,所以我仍然在分配给myURL之前需要以某种方式解开它(这是非可选的,因此与 as-is 分配不兼容)。

我可以通过使用中间变量来解决这个问题:

    guard let theURL = NSURL(string: "http://www.google.com") else {
        fatalError()
    }

    myURL = theURL

......但这显然不是优雅的。

我该怎么办?

1 个答案:

答案 0 :(得分:6)

更新另一种不使用guard的方法是使用switch作为选项映射到Optional枚举:

init?() {
    switch URL(string: "http://www.google.com") {
    case .none:
        myURL = NSURL()
        return nil
    case let .some(url):
        myURL = url
    }
}

虽然您仍然可以获得url本地变量。

原始回答

您可以将初始化程序声明为可用的初始化程序,并在url字符串解析失败时返回nil,而不是抛出致命错误。这将使客户端更清楚您的类初始化程序可能在某些时候失败。不过,你仍然不会摆脱guard

init?() {

    guard let url = URL(string: "http:www.google.com") else {
        // need to set a dummy value due to a limitation of the Swift compiler
        myURL = URL()
        return nil
    }
    myURL = url

}

这会在调用方面增加一点复杂性,因为它需要检查对象创建是否成功,但如果对象初始化程序无法构造对象,则建议使用该模式。您还需要放弃NSObject继承,因为您无法使用可用版本(init)覆盖init?

您可以在Swift blogApple's documentation或此SO question上找到有关可投放初始值设定项的详细信息。