0

我有如下模型。

struc Info: Decodable {
    var firstName: String?
    var lastName: String?
}

在表格视图单元格中显示时,我正在做的事情如下。

personName.text = "\(personArray[indexPath.row].firstName!) \(personArray[indexPath.row].lastName!)"

现在,如果我有以下格式的数据,应用程序就会崩溃

[
    {
        "firstName" : "F 1",
        "lastName" : "L 1"
    },
    {
        "firstName" : "F 2"
    },
    {
        "lastName" : "L 3"
    }
]

该应用程序崩溃说 lastName 是 nil


解决方案 1

此检查的解决方案是 nil & then show name,但是我不想在运行时进行检查,因为我必须检查所有变量(考虑到我有 25 个变量的模型)。下面是我可以做的。

var firstName = ""
if (personArray[indexPath.row].firstName == nil) {
    firstName = ""
} else {
    firstName = personArray[indexPath.row].firstName!
}

var lastName = ""
if (personArray[indexPath.row].lastName == nil) {
    lastName = ""
} else {
    lastName = personArray[indexPath.row].lastName!
}

personName.text = "\(firstName) \(lastName)"

解决方案 2

我可以在模型本身中进行更新,如下所示。

struc Info: Decodable {
    var firstName: String?
    var lastName: String?

    var firstName2 : String? {
    get {
        if (self.firstName==nil) {
            return ""
        }
        return firstName
    }

    var lastName2 : String? {
    get {
        if (self.lastName==nil) {
            return ""
        }
        return lastName
    }
}

personName.text = "\(personArray[indexPath.row].firstName2!) \(personArray[indexPath.row].lastName2!)"

但是我也有这个问题。这样,我必须再次创建 N 个变量。

如果 Web 服务中缺少该变量,是否还有其他替代方法可以分配默认值?

4

1 回答 1

0

我会推荐以下两种选择之一:

  1. 将计算属性添加到结构以确定显示名称。
  2. 手动解码,提供默认值。(如果需要,还可以添加显示名称属性)

就个人而言,我喜欢选项 1。我认为它最紧凑,也最容易维护。

选项 1 示例:

struct Info1: Decodable {
    var firstName: String?
    var lastName: String?

    var displayName: String {
        return [self.firstName, self.lastName]
            .compactMap { $0 } // Ignore 'nil'
            .joined(separator: " ") // Combine with a space
    }
}

print(Info1(firstName: "John", lastName: "Smith").displayName)
// Output: "John Smith"

print(Info1(firstName: "John", lastName: nil).displayName)
// Output: "John"

print(Info1(firstName: nil, lastName: "Smith").displayName)
// Output: "Smith"

print(Info1(firstName: nil, lastName: nil).displayName)
// Output: ""

选项 2 示例:

struct Info2: Decodable {
    var firstName: String
    var lastName: String

    enum CodingKeys: String, CodingKey {
        case firstName, lastName
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        self.firstName = try container.decodeIfPresent(String.self, forKey: .firstName) ?? ""
        self.lastName = try container.decodeIfPresent(String.self, forKey: .lastName) ?? ""
    }

    // Optional:
    var displayName: String {
        return [self.firstName, self.lastName]
            .compactMap { $0.isEmpty ? nil : $0 } // Ignore empty strings
            .joined(separator: " ") // Combine with a space
    }

    // TEST:
    init(from dict: [String: Any]) {
        let data = try! JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
        self = try! JSONDecoder().decode(Info2.self, from: data)
    }
}

print(Info2(from: ["firstName": "John", "lastName": "Smith"]).displayName)
// Output: "John Smith"

print(Info2(from: ["lastName": "Smith"]).displayName)
// Output: "Smith"

print(Info2(from: ["firstName": "John"]).displayName)
// Output: "John"

print(Info2(from: [String: Any]()).displayName)
// Output: ""
于 2018-05-29T03:22:55.103 回答