Swift

时间:2019-07-11 04:46:19

标签: swift class struct init

我有一个名为User的类初始化,而User类包含一些参数。现在在Offer类中,您可以看到我将User类作为参数传递,但是我希望将其作为可选参数。有没有办法在您的参数中有一个可选的类?谢谢

struct User {
    let uid: String
    let username: String

    init(uid: String, dictionary: [String: Any]) {
        self.uid = uid
        self.username = dictionary["username"] as? String ?? ""
    }
}

struct Offer {
    let user: User
    let caption: String
    let imageURL: String
    let creationDate: Date

    init(user: User, dictionary: [String: Any]) {
        self.user = user
        self.caption = dictionary["caption"] as? String ?? ""
        self.imageURL = dictionary["image_url"] as? String ?? ""

        let secondsFrom1970 = dictionary["creation_date"] as? Double ?? 0
        self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
    }
}

2 个答案:

答案 0 :(得分:1)

您的代码混淆了两个不同的事情:使用对象的一组成员值初始化对象,以及从字典中提取这些成员。只需编写两个单独的初始化器:

import Foundation

struct User {
    let uid: String
    let username: String

    /*
    // Due to the absence of an explicit initializer declaration,
    // the compiler will synthesize an implicit member-wise initailizer like this:
    init(uid: String, username: String) {
        self.uid = uid
        self.username = username
    }
    */
}

extension User {
    // Putting this initializer in an extension preserves he member-wise intializer
    init?(fromDict dict: [String: Any]) {
        guard let uid = dict["uid"] as? String,
              let username = dict["username"]  as? String
        else { return nil }

        self.init(uid: uid, username: username)
    }
}

struct Offer {
    let user: User
    let caption: String
    let imageURL: String
    let creationDate: Date

    /*
    // Due to the absence of an explicit initializer declaration,
    // the compiler will synthesize an implicit member-wise initailizer like this:
    init(
        user: User,
        caption: String,
        imageURL: String,
        creationDate: Date
    ) {
        self.user = user
        self.caption = caption
        self.imageURL = imageURL
        self.creationDate = creationDate
    }
    */
}

extension Offer {
    // Putting this initializer in an extension preserves he member-wise intializer
    init?(fromDict dict: [String: Any]) {
        guard let user = dict["user"] as? User,
              let caption = dict["caption"] as? String,
              let imageURL = dict["image_url"] as? String,
              let secondsFrom1970 = dict["creation_date"] as? Double
        else { return nil }

        self.init(
            user: user,
            caption: caption,
            imageURL: imageURL,
            creationDate: Date(timeIntervalSince1970: secondsFrom1970)
        )
    }
}

一些注意事项:

  1. ??的情况下,使用nil-coalescing运算符(nil)提供无意义的默认值确实是一种不好的做法。它隐藏了故障,并无声地引入了数据完整性问题;不要这样做。
  2. String对于名为imageURL的成员来说是不合适的类型。使用URL
  3. 如果这些命令来自JSON,请使用Codable协议来自动化所有这些样板代码。
  4. String对于ID来说是一种较差的类型,主要是因为与UUIDInt等更合适的类型相比,它确实很慢。这在大多数数据库中尤其如此,其中文本比较比Int / UUID比较慢得多。

答案 1 :(得分:0)

首先这不是class,而是struct,两者都不一样。

您可以轻松创建可选参数,如下所示。 您还需要将user属性标记为可选。

struct Offer {
    let user: User?
    let caption: String
    let imageURL: String
    let creationDate: Date

    init(user: User? = nil, dictionary: [String: Any]) {
        self.user = user
        self.caption = dictionary["caption"] as? String ?? ""
        self.imageURL = dictionary["image_url"] as? String ?? ""

        let secondsFrom1970 = dictionary["creation_date"] as? Double ?? 0
        self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
    }
}