Swiftの下の辞書(json)とモデルの変換
11989 ワード
一、swiftの下でOCフレームを使用する
OCの下で辞書とモデルの変換は非常に使いやすいサードパーティのフレームワーク(YYMode,MJExtensionなど)がありますが、もちろんSwiftはこの2つのフレームワークを参考にすることもできますが、モデルを作成する際にNSObjectから継承し、キーワード@objcMembersを加えるだけでいいです.
swift原生Codableプロトコルの使用
1、オリジナルのCodableプロトコルを使用する場合、現在のクラス継承プロトコルCodableが必要であり、swiftの列挙、構造体、クラスのみがこのプロトコルを継承することができる.これっぽっちのことはOCではできません.
2.Codableプロトコルを使用する場合は、モデルと元のjsonデータとの間のkey値の一貫性を確保する必要があります.json辞書には以下のようなものが入っています(ここで私が使っている辞書)
モデルは次のように実現する必要があります(もちろんこれは理想的な状態です)
3、モデルに(name_op)のようなフィールドがあり、元のjsonデータに値がない場合、モデルは次のようになります.
モデルに解析すると失敗します.不確定な値をオプションタイプとして定義する必要があります.元のjsonデータがこのフィールドを持っているかどうかにかかわらず、解析に成功します.もしそうでなければ、この属性はnilです.
4、モデルが設計されている場合、元のjsonデータの中にフィールドとあなたのフィールドが衝突している場合(属性がnickで元のデータがnick_nameである場合)、この値は解析に成功しません.オプションであれば、少なくとも成功します.そうしないと失敗します.解決策はenum CodingKeys:String,CodingKey{}というマッピング関係を実現することである.
5、もしあなたのモデルの中にネスト関係があるならば、例えばあなたのモデルの中に他のモデルあるいはモデルの配列があるならば、ネストしたモデルの中で依然として対応するプロトコルを実現していることを保証して、現在のモデルと同じようにすればいいです.
6、モデルの中と元のデータの中のタイプが統一されていないと、この解析も失敗に終わります.この場合、現在のプロパティに適したクラスをカスタマイズする必要があります.最も一般的なのは(BoolとInt,IntとString)これらがバックグラウンドの若型言語で区別されていないことです.だからどんなタイプなのか分からないし、勝手に定義したら失敗します.BoolまたはIntのいずれかのタイプを定義します.
以下はIntまたはStringタイプの
モデルを設計する際、以下のように値を付けます.
上記の手順を完了すれば、辞書モデルの変換の大きな部分の問題を基本的に解決することができます.私がデザインしたモデルを貼り付けます.
作成された辞書
三、モデル変換用JSOnDecoder、JSOnDecoderはDataタイプが必要なので、まずjsonをDataに変換する.
四、共通するために、辞書モデルを変換するツールクラスを設計する.
使用
OCの下で辞書とモデルの変換は非常に使いやすいサードパーティのフレームワーク(YYMode,MJExtensionなど)がありますが、もちろんSwiftはこの2つのフレームワークを参考にすることもできますが、モデルを作成する際にNSObjectから継承し、キーワード@objcMembersを加えるだけでいいです.
@objcMembers class CDBaseModel: NSObject, YYModel {
//swift YYModel
var name:String = ""
var age:Int = 0
var uid:String = ""
static func modelCustomPropertyMapper() -> [String : Any]? {
return [
"uid":"id",
]
}
}
swift原生Codableプロトコルの使用
1、オリジナルのCodableプロトコルを使用する場合、現在のクラス継承プロトコルCodableが必要であり、swiftの列挙、構造体、クラスのみがこのプロトコルを継承することができる.これっぽっちのことはOCではできません.
enum Gender:String, Decodable {
case male
case female
case other
}
struct BookModel:Codable {
var name:String = ""
var price:Float = 0
}
class PersonModel: NSObject, Codable {
var name:String = ""
}
2.Codableプロトコルを使用する場合は、モデルと元のjsonデータとの間のkey値の一貫性を確保する必要があります.json辞書には以下のようなものが入っています(ここで私が使っている辞書)
private var dictionary:[String:Any] = [:]
self.dictionary["name"] = " "
self.dictionary["age"] = 9
self.dictionary["sex"] = true
モデルは次のように実現する必要があります(もちろんこれは理想的な状態です)
struct UserModel:Codable {
var name: String = ""
var age: Int = 0
var sex: Bool = false
}
3、モデルに(name_op)のようなフィールドがあり、元のjsonデータに値がない場合、モデルは次のようになります.
struct UserModel:Codable {
var name: String = ""
var age: Int = 0
var sex: Bool = false
var name_op: String = ""
}
モデルに解析すると失敗します.不確定な値をオプションタイプとして定義する必要があります.元のjsonデータがこのフィールドを持っているかどうかにかかわらず、解析に成功します.もしそうでなければ、この属性はnilです.
struct UserModel:Codable {
var name: String = ""
var age: Int = 0
var sex: Bool = false
var name_op: String?
}
4、モデルが設計されている場合、元のjsonデータの中にフィールドとあなたのフィールドが衝突している場合(属性がnickで元のデータがnick_nameである場合)、この値は解析に成功しません.オプションであれば、少なくとも成功します.そうしないと失敗します.解決策はenum CodingKeys:String,CodingKey{}というマッピング関係を実現することである.
struct UserModel:Codable {
var name: String = ""
var age: Int = 0
var sex: Bool = false
var name_op: String?
var nick: String?
enum CodingKeys: String, CodingKey {
case name
case age
case sex
case name_op
case nick = "nick_name"
}
}
5、もしあなたのモデルの中にネスト関係があるならば、例えばあなたのモデルの中に他のモデルあるいはモデルの配列があるならば、ネストしたモデルの中で依然として対応するプロトコルを実現していることを保証して、現在のモデルと同じようにすればいいです.
struct UserModel:Codable {
var name: String = ""
var age: Int = 0
var sex: Bool = false
var name_op: String?
var nick: String?
// ( Codable )
var animo_op: AnimalModel?
var books_op: [BookModel]?
enum CodingKeys: String, CodingKey {
case name
case age
case sex
case name_op
case nick = "nick_name"
}
}
6、モデルの中と元のデータの中のタイプが統一されていないと、この解析も失敗に終わります.この場合、現在のプロパティに適したクラスをカスタマイズする必要があります.最も一般的なのは(BoolとInt,IntとString)これらがバックグラウンドの若型言語で区別されていないことです.だからどんなタイプなのか分からないし、勝手に定義したら失敗します.BoolまたはIntのいずれかのタイプを定義します.
struct TIntBool:Codable {
var int:Int {
didSet {
if int == 0 { self.bool = false
} else { self.bool = true }
}
}
var bool:Bool {
didSet {
if bool { self.int = 1
} else { self.int = 0 }
}
}
// ( )
init(from decoder: Decoder) throws {
let singleValueContainer = try decoder.singleValueContainer()
if let intValue = try? singleValueContainer.decode(Int.self) {
self.int = intValue
self.bool = (intValue != 0)
} else if let boolValue = try? singleValueContainer.decode(Bool.self) {
self.bool = boolValue
if boolValue { self.int = 1
} else { self.int = 0 }
} else {
self.bool = false
self.int = 0
}
}
}
以下はIntまたはStringタイプの
struct TStrInt: Codable {
var int:Int {
didSet {
let stringValue = String(int)
if stringValue != string {
string = stringValue
}
}
}
var string:String {
didSet {
if let intValue = Int(string), intValue != int {
int = intValue
}
}
}
// ( )
init(from decoder: Decoder) throws {
let singleValueContainer = try decoder.singleValueContainer()
if let stringValue = try? singleValueContainer.decode(String.self)
{
string = stringValue
int = Int(stringValue) ?? 0
} else if let intValue = try? singleValueContainer.decode(Int.self)
{
int = intValue
string = String(intValue);
} else
{
int = 0
string = ""
}
}
}
モデルを設計する際、以下のように値を付けます.
struct UserModel:Codable {
var name: String = ""
var age: Int = 0
var sex: Bool = false
var name_op: String?
var nick: String?
// ( Codable )
var animo_op: AnimalModel?
var books_op: [BookModel]?
// ( Int, String, 、 、 )
var stringInt: TStrInt?
var boolInt: TIntBool?
enum CodingKeys: String, CodingKey {
case name
case age
case sex
case name_op
case nick = "nick_name"
case animo_op
case animo_op
case stringInt
case boolInt
}
}
上記の手順を完了すれば、辞書モデルの変換の大きな部分の問題を基本的に解決することができます.私がデザインしたモデルを貼り付けます.
struct UserModel:Codable {
//1、 ( , )
var name: String = ""
var age: Int = 0
var sex: Bool = false
var weight: Double = 0
var height: Float = 0
var animo: AnimalModel = AnimalModel.init()
var books: [BookModel] = []
//2、 ( , , )
var name_op: String?
var age_op: Int?
var sex_op: Bool?
var weight_op: Double?
var height_op: Float?
var animo_op: AnimalModel?
var books_op: [BookModel]?
//3、key ( key , ‘CodingKeys’ )
var nick: String = "" // nick_name
var nick_op: String? // nick_optional
//4、 ( Int, String, 、 、 )
var birthday: TStrInt?
var stringInt: TStrInt?
var birthday_op:TStrDou?
var stringDou: TStrDou?
var boolInt: TIntBool?
var intBool: TIntBool?
// key 。
enum CodingKeys: String, CodingKey {
case name
case age
case sex
case weight
case height
case animo
case books
case name_op
case age_op
case sex_op
case weight_op
case height_op
case animo_op
case books_op
case nick = "nick_name"
case nick_op = "nick_optional"
case birthday
case stringInt
case birthday_op
case stringDou
case boolInt
case intBool
}
}
struct AnimalModel:Codable {
var name:String = ""
}
struct BookModel:Codable {
var name:String = ""
var price:Float = 0
}
作成された辞書
func setupData() {
self.dictionary["name"] = " "
self.dictionary["age"] = 9
self.dictionary["sex"] = true
self.dictionary["weight"] = 177.7
self.dictionary["height"] = 77.7
self.dictionary["animo"] = ["name":" "]
self.dictionary["books"] = [["name":" ", "price":22],["name":" ", "price":33]]
self.dictionary["name_op"] = "tiangwang"
self.dictionary["age_op"] = 11
self.dictionary["sex_op"] = false
self.dictionary["weight_op"] = 22.2
self.dictionary["height_op"] = 22.2
self.dictionary["animo_op"] = ["name":" "]
self.dictionary["books_op"] = [["name":" ", "price":11.5],["name":" ", "price":11.6]]
self.dictionary["nick_name"] = " "
self.dictionary["nick_optional"] = " "
self.dictionary["birthday"] = 20000102
self.dictionary["stringInt"] = "123"
self.dictionary["birthday_op"] = 123456.5
self.dictionary["stringDou"] = "321"
self.dictionary["boolInt"] = true
self.dictionary["intBool"] = 1
}
三、モデル変換用JSOnDecoder、JSOnDecoderはDataタイプが必要なので、まずjsonをDataに変換する.
guard let data = try? JSONSerialization.data(withJSONObject: self.dictionary, options: JSONSerialization.WritingOptions.init()) else {
print(" JSON ")
return
}
guard let model = try? JSONDecoder.init().decode(UserModel.self, from: data) else {
print("model ,)")
return
}
print("model = \(model)")
四、共通するために、辞書モデルを変換するツールクラスを設計する.
struct CDModel {
// (json)
static public func jsonToModel(type:T.Type, json:Any) -> T? where T:Codable {
guard let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) else {
return nil
}
guard let model = try? JSONDecoder.init().decode(type, from: jsonData) else {
return nil
}
return model
}
//json
static public func jsonToModel(type:T.Type, array:[[String:Any]]) -> [T]? where T:Codable {
guard let jsonData = try? JSONSerialization.data(withJSONObject: array, options: []) else {
return nil
}
guard let result = try? JSONDecoder.init().decode([T].self, from: jsonData) else {
return nil
}
return result
}
// json
public static func modelToJson(toString model:T) -> String? where T:Encodable {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
guard let data = try? encoder.encode(model)else{
return nil
}
guard let jsonStr = String(data: data, encoding: .utf8)else{
return nil
}
return jsonStr
}
// json
public static func modelToJson(toDictionary model:T) -> [String:Any]? where T:Encodable{
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
guard let data = try? encoder.encode(model) else {
return nil
}
guard let dict = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves)as? [String:Any] else {
return nil
}
return dict
}
}
使用
guard let model = CDModel.jsonToModel(type: UserModel.self, json: self.dictionary) else {
return
}
print("model = \(model)")
let array = CDModel.jsonToModel(type: UserModel.self, array: [self.dictionary])
print("array = \(array ?? [])")