具有非可选属性的便捷初始化程序

时间:2015-03-16 21:15:25

标签: swift initialization optional

我的一个对象有一个整数ID。由于这是一个必需的属性,我没有将它定义为可选,我在指定的初始化程序中要求它:

class Thing {

    var uniqueID: Int
    var name: String?

    init (uniqueID: Int) {
        self.uniqueID = uniqueID
    }       

}

由于我是从一些JSON创建其中一个,因此用法如下:

if let uniqueID = dictionary["id"] as? Int {
    let thing = thing(uniqueID: unique)
}

(顺便说一下,我希望对我到目前为止所做的事情进行健全检查。)

接下来,我希望能够为Thing类添加一个便利初始化器,它接受字典对象并相应地设置属性。这包括所需的uniqueID和其他一些可选属性。到目前为止,我的最大努力是:

convenience init (dictionary: [String: AnyObject]) {
    if let uniqueID = dictionary["id"] as? Int {
        self.init(uniqueID: uniqueID)
        //set other values here?
    }
        //or here?
}

但当然这还不够,因为未在条件的所有路径上调用指定的初始值设定项。

我该如何处理这种情况?它甚至可能吗?或者我应该接受uniqueID必须是可选的吗?

2 个答案:

答案 0 :(得分:5)

你有几个选择。一个是failable initialisers

convenience init?(dictionary: [String: AnyObject]) {
    if let uniqueID = dictionary["id"] as? Int {
        self.init(uniqueID: uniqueID)
    } else {
        self.init(uniqueID: -1)
        return nil
    }
}

从技术上讲,这可以稍微调整一下(主要取决于你的喜好/ swift的版本),但我个人的偏好如下:

class func fromDictionary(dictionary: [String: AnyObject]) -> Thing? {
    if let uniqueID = dictionary["id"] as? Int {
        return self.init(uniqueID: uniqueID)
    }

    return nil
}

一起作为一个游乐场:

class Thing {
    var uniqueID: Int
    var name: String?

    init(uniqueID: Int) {
        self.uniqueID = uniqueID
    }

    convenience init?(dictionary: [String: AnyObject]) {
        if let uniqueID = dictionary["id"] as? Int {
            self.init(uniqueID: uniqueID)
        } else {
            self.init(uniqueID: -1)
            return nil
        }
    }

    class func fromDictionary(dictionary: [String: AnyObject]) -> Thing? {
        if let uniqueID = dictionary["id"] as? Int {
            return self.init(uniqueID: uniqueID)
        }

        return nil
    }
}

let firstThing = Thing(uniqueID: 1)
let secondThing = Thing(dictionary: ["id": 2])
let thirdThing = Thing(dictionary: ["not_id": 3])
let forthThing = Thing.fromDictionary(["id": 4])
let fithThing = Thing.fromDictionary(["not_id": 4])

答案 1 :(得分:4)

最好的解决方案可能是使用一个可用的初始化程序,它将返回一个实例化的对象或nil

因为Swift对象不能部分构造,并且便捷初始化器必须调用非便利初始化器,所以我们仍然必须在失败的情况下做一些事情。

结果将如下所示:

convenience init?(dictionary: [String: AnyObject]) {
    if let uniqueID = dictionary["id"] as? Int {
        self.init(uniqueID: uniqueID)
    } else {
        self.init(uniqueID: 0)
        return nil
    }
}

一般来说,我们的非便利初始化程序应该是接受所有参数的程序,而方便初始化程序应该是不需要某些参数的方法。

例如,我可能会使我的默认初始化程序看起来像这样:

init(uniqueID: Int, name: String? = nil) {
    self.uniqueID = uniqueID
    self.name = name
}

这允许我们以几种不同的方式调用构造函数:

let thing1 = Thing(1)
let thing2 = Thing(2, nil)
let thing3 = Thing(3, "foo")
let thing4 = Thing(4, myUnwrappedStringVar)
let thing5 = Thing(5, myWrappedStringOptional)

这已经为我们提供了很多用例。

所以,让我们添加一个接受可选Int的便利初始值设定项。

convenience init?(uniqueID: Int? = nil, name: String? = nil) {
    if let id = uniqueID {
        self.init(uniqueID: id, name: name)
    } else {
        self.init(uniqueID: 0)
        return nil
    }
}

现在我们可以为我们的Int?参数设置一个uniqueID,当它nil时失败。

所以,还有一个接受字典。

convenience init?(dictionary: [String: AnyObject]) {
    let uniqueID = dictionary["id"] as? Int
    let name = dictionary["name"] as? String
    self.init(uniqueID: uniqueID, name: name)
}

在我们的第一个便利构造函数中,我们仍然有一些稍微奇怪的初始化然后返回nil模式,但是我们在此基础上构建的所有其他内容都可以简单地调用那个便利初始化程序而不是&#39 ; t需要奇怪的模式。

在获取字典的初始值设定项中,如果没有id键,或者它的某些内容不是Int,那么{{ 1}}将是let uniqueID,所以当我们调用其他构造函数时,它将调用接受nil的那个,传递Int?,返回nil,因此我们调用的那个将返回nil