Быстрый словарь с типами смешивания (необязательно и не обязательно) - PullRequest
0 голосов
/ 25 сентября 2018

У меня есть структура, у которой есть метод для возврата в словарное представление.Переменные-члены представляли собой комбинацию различных типов (String и Double?)

. В следующем примере кода было бы предупреждение от 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 голосов
/ 25 сентября 2018

Вы можете разыграть frequency до Any, так как последний может содержать любой тип.Это похоже на приведение экземпляров определенного типа Swift к типу идентификатора Objective-C.В конце концов, вам придется понизить объекты типа Any до определенного класса, чтобы иметь возможность вызывать методы и получать доступ к свойствам.

Я бы не рекомендовал структурировать данные в вашем коде, используя Any, или если вы хотите быть конкретным 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")
0 голосов
/ 25 сентября 2018

Я бы рекомендовал добавить 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 просто не получают записи в выходном словаре.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...