web-dev-qa-db-ja.com

Swiftオブジェクトを辞書に変換する方法

私はiOSプログラミングには比較的慣れていません。ただし、SwiftはオブジェクトをJSONに、またはその逆に自動変換する方法を備えていると想定していました。

しかしながら...

どのようにデータをWebサービスに投稿しても(AlamoFireのようなものを使用する場合でも)、リクエストは辞書でなければならないようです。これらのフォーラムはすべて、返されたJSON文字列をオブジェクトに変換するのがいかに簡単かという例を示しています。本当です。ただし、リクエストは手動でコーディングする必要があります。つまり、すべてのオブジェクトプロパティを調べて、それらを辞書としてマップします。

だから私の質問はこれです:私は何かを見逃していますか?これはすべて間違っていて、(a)REQUESTで(辞書の代わりに)JSONを送信するか、(b)オブジェクトを辞書に自動的に変換する非常に簡単な方法がありますか?

繰り返しになりますが、JSON応答を処理するのがいかに簡単かを確認します。 Webサービスに投稿したいリクエストオブジェクトを、AlamoFireなどのライブラリが必要とする形式に自動的に変換する方法を探しています。他の言語ではこれはかなり簡単なことなので、Swiftでも同様に簡単で自動化された方法があることを望んでいます。

30
JL Gradley

Swiftは現在、JavaまたはC#のような高度なリフレクションをサポートしていません。そのため、答えは次のとおりです。

[更新] Swift 4にはCodableプロトコルがあり、JSONおよびPLISTとのシリアル化が可能です。

typealias Codable = Decodable & Encodable
8
Darko

私は@Darkoに反対しなければなりません。

Swift 2では、

プロトコル指向プログラミングおよびMirror classが提供する単純なリフレクションを使用します。

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
45
fencingCode

リフレクションを使用せず、ネストされたオブジェクトで動作します(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関数にさらに値の型を追加できます。

ObjectMapper ライブラリを使用することもできます。オブジェクトを辞書に変換する「toJSON」メソッドがあります。

3
Remy Cilia