Подтвердить что ты не робот

Как преобразовать объект Swift в словарь

Я относительно новичок в программировании на iOS. Тем не менее, я бы предположил, что Swift будет иметь автоматический способ преобразования объектов в JSON и наоборот. При этом я нашел несколько библиотек, которые могут это сделать.

ОДНАКО...

Кажется, что независимо от того, как вы отправляете данные в веб-службу (даже используя что-то вроде AlamoFire), запросы должны быть словарем. Все эти форумы показывают примеры того, как легко преобразовать возвращенную строку JSON в объекты. Правда. Но запрос должен быть закодирован вручную. То есть, пройдите все свойства объекта и сопоставьте их как словарь.

Итак, мой вопрос: я что-то упустил? Имею ли я все это неправильно и есть супер-простой способ: (a) отправить JSON (вместо словаря) в REQUEST или (b) автоматически преобразовать объект в словарь?

Опять же, я вижу, как легко справиться с ответом JSON. Я просто ищу автоматический способ преобразования объекта запроса, который я хочу опубликовать, в веб-службу в формате, который требуется для библиотеки, такой как AlamoFire (или что-то еще). С другими языками это довольно тривиально, поэтому я надеюсь, что с Swift будет такой же легкий и автоматический способ.

4b9b3361

Ответ 1

В настоящее время Swift не поддерживает расширенное отражение, например, Java или С#, поэтому ответ таков: нет, нет простого и автоматизированного способа с чистым Swift.

[Обновление] Swift 4 имеет протокол Codable, который позволяет сериализоваться в/из JSON и PLIST.

typealias Codable = Decodable & Encodable

Ответ 2

Я должен не согласиться с @Darko.

В Swift 2,

используйте протокол-ориентированное программирование и простое отражение, предлагаемое классом Зеркало:

protocol JSONAble {}

extension JSONAble {
    func toDict() -> [String:Any] {
        var dict = [String:Any]()
        let otherSelf = Mirror(reflecting: self)
        for child in otherSelf.children {
            if let key = child.label {
                dict[key] = child.value
            }
        }
        return dict
    }
}

то вы можете использовать этот протокол с вашим классом запроса и создать нужный словарь:

class JsonRequest : JSONAble {
    var param1 : String?
    // ...
}

let request = JsonRequest()
// set params of the request
let dict = request.toDict()
// use your dict

Ответ 3

Без использования отражения и работает для вложенных объектов (Swift 4):

protocol Serializable {
    var properties:Array<String> { get }
    func valueForKey(key: String) -> Any?
    func toDictionary() -> [String:Any]
}

extension Serializable {
    func toDictionary() -> [String:Any] {
        var dict:[String:Any] = [:]

        for prop in self.properties {
            if let val = self.valueForKey(key: prop) as? String {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Int {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Double {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Array<String> {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Serializable {
                dict[prop] = val.toDictionary()
            } else if let val = self.valueForKey(key: prop) as? Array<Serializable> {
                var arr = Array<[String:Any]>()

                for item in (val as Array<Serializable>) {
                    arr.append(item.toDictionary())
                }

                dict[prop] = arr
            }
        }

        return dict
    }
}

Просто реализуйте свойства и valueForKey для настраиваемых объектов, которые вы хотите преобразовать. Например:

class Question {
    let title:String
    let answer:Int

    init(title:String, answer:Int) {
        self.title = title
        self.answer = answer
    }
}
extension Question : Serializable {
    var properties: Array<String> {
        return ["title", "answer"]
    }

    func valueForKey(key: String) -> Any? {
        switch key {
        case "title":
            return title
        case "answer":
            return answer
        default:
            return nil
        }
    }
} 

Вы можете добавить больше значений в функцию toDictionary, если вам нужно.

Ответ 4

Вы также можете использовать библиотеку ObjectMapper. Он имеет метод "toJSON", который преобразует ваш объект в словарь.

Ответ 5

Мое решение этого будет примерно таким:

extension Encodable {

    var dict : [String: Any]? {
        guard let data = try? JSONEncoder().encode(self) else { return nil }
        guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] else { return nil }
        return json
    }
}

и использование будет примерно таким:

movies.compactMap { $0.dict }