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

Ben*_*ard 4 initialization optional swift

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

class Thing {

    var uniqueID: Int
    var name: String?

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

}
Run Code Online (Sandbox Code Playgroud)

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

if let uniqueID = dictionary["id"] as? Int {
    let thing = Thing(uniqueID: unique)
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

Jos*_*ffy 5

你有几个选择.一个是可用的初始化者:

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

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

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

    return nil
}
Run Code Online (Sandbox Code Playgroud)

所有在一起,作为一个操场:

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])
Run Code Online (Sandbox Code Playgroud)


nhg*_*rif 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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

例如,我可能会让我的默认初始化程序如下所示:

init(uniqueID: Int, name: String? = nil) {
    self.uniqueID = uniqueID
    self.name = name
}
Run Code Online (Sandbox Code Playgroud)

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

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

这已经涵盖了我们的很多用例。

因此,让我们添加另一个接受可选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
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以用 anInt?来作为我们的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)
}
Run Code Online (Sandbox Code Playgroud)

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

在接受字典的初始化器中,如果没有id键,或者它不是 an Int,那么它将let uniqueIDnil,所以当我们调用另一个构造函数时,它将调用接受 an Int?、 be pass nil、 return的构造函数nil,因此我们打电话的那个人会回来的nil