具有混合类型(可选和非可选)的Swift字典

时间:2018-09-25 18:33:54

标签: swift dictionary optional

我有一个结构,该结构具有返回字典表示形式的方法。成员变量是不同类型(字符串和双精度?)的组合

在下面的代码示例中,Xcode将发出警告(表达式从'Double?'隐式强制为Any)

struct Record {
  let name: String
  let frequency: Double?

  init(name: String, frequency: Double?) {
    self.name = name
    self.frequency = frequency
  }

  func toDictionary() -> [String: Any] {
    return [
      "name": name,
      "frequency": frequency
    ]
  }
}

但是,如果返回类型[String:Any?],则警告消失:

struct Record {
  let name: String
  let frequency: Double?

  init(name: String, frequency: Double?) {
    self.name = name
    self.frequency = frequency
  }

  func toDictionary() -> [String: Any?] {
    return [
      "name": name,
      "frequency": frequency
    ]
  }
}

我的问题是:这是正确的吗?如果是的话,您能指出一些解释这个问题的Swift文档吗?

如果不是,应该是什么?

==编辑==

以下内容也适用:

struct Record {
  let name: String
  let frequency: Double?

  init(name: String, frequency: Double?) {
    self.name = name
    self.frequency = frequency
  }

  func toDictionary() -> [String: Any] {
    return [
      "name": name,
      "frequency": frequency as Any
    ]
  }
}

2 个答案:

答案 0 :(得分:1)

您可以将frequency强制转换为Any,因为后者可以容纳 any 类型。就像将特定Swift类型的实例转换为Objective-C id类型一样。最终,您必须将Any类型的对象下放到特定的类中,以便能够调用方法和访问属性。

我不建议您使用Any来构造代码中的数据,或者如果您想指定特定的Any?(对象可能包含或不包含 some 值时), 。那可能是不良的数据建模的迹象。

来自documentation

  

Any 可以表示任何类型的实例,包括函数类型。[...]使用 Any AnyObject ,当您明确需要它们提供的行为和功能时。 最好始终明确说明您希望在代码中使用的类型。

(重点是我的)

请使用Data类型。这样您就可以解码Record或将其编码到Data中:

struct Record : Codable {
    let name: String
    let frequency: Double?

    init(name: String, frequency: Double?) {
        self.name = name
        self.frequency = frequency
    }

    init(data: Data) throws { 
        self = try JSONDecoder().decode(Record.self, from: data) 
    }

    func toData() -> Data {
        guard let data = try? JSONEncoder().encode(self) else {
            fatalError("Could not encode Record into Data")
        }
        return data
    }
}

并像这样使用它:

let record = Record(name: "Hello", frequency: 13.0)
let data = record.toData()

let decodedRecord = try Record(data: data)
print(decodedRecord.name)
print(decodedRecord.frequency ?? "No frequency")

答案 1 :(得分:0)

我建议添加Codable一致性,并让JSONEncoder完成所有繁重的工作。但是,如果您受制于toDictionary方法,那么我建议不要使用[String:Any?],因为这可能导致不确定的行为(尝试打印字典以获取更多详细信息)。

toDictionary的可能解决方案是使用元组数组,将其转换为字典:

func toDictionary() -> [String: Any] {
    let propsMap: [(String, Any?)] = [
        ("name", name),
        ("frequency", frequency)
    ]
    return propsMap.reduce(into: [String:Any]()) { $0[$1.0] = $1.1 }
}

这样,nil属性根本不会在输出字典中接收条目。