在Swift中如何在自定义初始化器中返回nil?

22

我正在尝试用Swift编写自定义初始化程序。我有类似这样的代码:

convenience init(datasource:SomeProtocol) {
    assert(datasource != nil, "Invalid datasource")
    if(datasource == nil) {
        return nil
    }
    self.init()
}

"return nil"这一行导致了错误:"找不到接受所提供参数的'__conversion'的重载"

所以,我想要做的就是如果调用者没有提供有效的数据源,则让这个便利初始化器返回nil。

我在这里做错了什么?

谢谢


您的程序在断言之后将不会继续执行。之后数据源为空的情况无需担心。 - drewag
现在有一个解决方案了。你应该考虑更改你接受的答案。 - Jarsen
4个回答

51

更新:从Xcode 6.1 beta 1开始(可以在Mac Dev Center中获取),Swift初始化器可以声明返回一个可选类型:

convenience init?(datasource:SomeProtocol) {
    if datasource == nil {
        return nil
    }
    self.init()
}

或者一个隐式解包的可选项:

convenience init!(datasource:SomeProtocol) {
    if datasource == nil {
        return nil
    }
    self.init()
}

我认为数据源类型应该是可选的 "SomeProtocol?"。 - Suryavel TR
@SuryavelTR:在问题中是那样的,而且它并不真正与问题相关,所以我把它留下了。它可能本来是可选的,但我想理论上可能会发生(虽然极不可能)SomeProtocol扩展了NilLiteralConvertible或其他类似情况。 - user102008

13

我认为这会奏效,尽管从你的留言中并不清楚你正在使用哪个数据源:

class func instOrNil(datasource:A) -> Self? {
    // do something with datasource
    if datasource.isValid() {
        return self()
    } else {
        return nil
    }
}

更新 Swift 3

现在您可以从 init?(...) 返回nil

init?(datasource: A){
    if datasource.isValid() {
        // initialise your properties from datasource
    } else {
        return nil
    }
}

你的代码可以运行,但不够高效。你将数据源设置为可选项(使用 **?**),然后验证是否有数据源。如果参数不是可选项(去掉 **?**),你需要确保该值不是可选项,这样就不必检查数据源是否有值了。在这种情况下,使用 if let 是没有用的,因为你不需要解包该值(你也不会使用它)。 - Emilie
@Emilie,你是正确的。不需要将其设置为可选项,然后再取消包装它。已更改代码。 - Grimxn
有没有一种使用初始化器而不是类方法来完成它的方法? - user102008
正如Emilie之前所说,init_xxx没有返回类型,因此不,你不能返回nil。 - Grimxn

3

这是因为initializers实际上不需要返回值。如果一个方法不需要返回类型,你就不能返回nil

想要达到你所试图做的事情(即强制你的类具有数据源),只需使你的数据源可选项。非可选变量必须有一个值(因此不能为nil)并且必须初始化。


这已经不准确了,因为Swift现在允许可选的初始化器。 - Alec O

1
如果这个类的超类是一个Objective-C类,并且你知道有一些输入会导致它的初始化程序返回nil,那么你可以简单地将该输入传递给超类的初始化程序,这将导致你的初始化程序返回nil:
import Foundation
class Foo : NSURL {
  convenience init(x: Int) {
    if x == 42 {
      self.init(string: "http://www.google.com/")
    } else {
      self.init(string: "not a url") // returns nil
    }
  }
}

let a: Foo? = Foo(x: 42)
println(a) // prints "Optional(http://www.google.com/)"
let b: Foo? = Foo(x: 17)
println(b) // prints "nil"

当然,这仅在你足够幸运地拥有一个初始化程序将返回nil的超类时才有效。因此,这不是一种通用解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接