class 初始化器中的可选 class 初始化器参数 Swift

Optional class initializer parameter in class initializer in Swift

我有一个名为 User 的 class init,class User 包含一些参数。现在在 Offer class 中,您可以看到我将 User class 作为参数传递,但我想将其作为可选参数。有没有办法在你的参数中有一个可选的 class ?谢谢

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)
    }
}

首先这不是 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)
    }
}

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

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 的情况下使用 nil-coalescing 运算符 (??) 提供 non-sensical 默认值是非常糟糕的做法。它隐藏故障并默默地引入数据完整性问题;别这样。
  2. String 不是名为 imageURL 的成员的合适类型。使用 URL.
  3. 如果这些命令来自 JSON,请使用 Codable 协议来自动化所有这些样板代码。
  4. String 对于 ID 来说是一个糟糕的类型,主要是因为与 UUIDInt 等更合适的类型相比,它真的很慢。在大多数数据库中尤其如此,其中文本比较比Int/UUID比较慢。