swift Codableの使用と簡単なパッケージ
21966 ワード
swiftは4.0までデータ解析の方法がなかった.現在4.0以降,Codableが直接jsonをオブジェクトに変換できるようになり,OCのKVCメカニズムに取って代わることが期待される.まずコダックを見てみましょう
きほんしよう
NSCodingに似ていて、decoderとencoderを書き換えることができます.基本的な使い方は簡単です
CodingKey
CodableといえばCodingKeyが欠かせませんが、上記の例はjsonデータがmodel属性に1つずつ対応している場合にのみ適用され、対応するkeyも一致しなければなりませんが、CodingKeyは開発中によく遭遇するバックグラウンドから与えられるkeyがappと異なる場合を解決することができます
また,一部のデータを受信する必要がない場合には,CodingKeyも扱うことができ,主にCodingKeysの列挙にこのkeyを書かないで済む.
パッヶージ
Codableのメカニズムに基づいて、プロジェクトに簡単にカプセル化することができます.現在よく見られるネットワークフレームワークでは、jsonデータを直接辞書に変換するため、辞書をjsonとjsonに変換する方法が追加されています.
使用
ここでmap完了後のコールバック法を追加したが,Codableの解析は,再オブジェクト属性のset法ではなく,OCのKVC原理とは異なるためである.したがって、いくつかの付与が完了した後の操作では、このコールバックメソッドを使用する必要があります.また、classとstructのタイプを区別し、対応する方法を選択することに注意する必要があります.
nullの処理
バックグラウンドで値ごとにnullが返される可能性があるというメッセージがあり、属性をオプションにしたくないのでnullの処理を増やし、nullに遭遇したら再init(from decoder:Decoder)throwsの方法が必要になる
decodeNil(forKey:KeyedDecodingContainer.Key)throws->Bool解析時に対応する属性がnull値であるか否かを判断し、trueを返すならnullでないならfalseを返す
以上のパッケージは、swiftが強力な言語であるため、jsonデータのタイプがmodelプロパティのタイプに対応していることに注意してください.そうしないと、解析に失敗します.
参照先:http://www.cocoachina.com/swift/20170630/19691.html
demo:https://github.com/NickQCX/CXMap/blob/master/README.md
public typealias Codable = Decodable & Encodable
きほんしよう
NSCodingに似ていて、decoderとencoderを書き換えることができます.基本的な使い方は簡単です
class Person: Codable {
var name : String = ""
var age : Int = 0
}
//json
let JSONString = "{"name":"xiaoming","age":10}"
guard let jsonData = JSONString.data(using: .utf8) else {
return
}
let decoder = JSONDecoder()
guard let obj = try? decoder.decode(Person.self, from: jsonData) else {
return
}
print(obj.name) //xiaoming
print(obj.age) //10
CodingKey
CodableといえばCodingKeyが欠かせませんが、上記の例はjsonデータがmodel属性に1つずつ対応している場合にのみ適用され、対応するkeyも一致しなければなりませんが、CodingKeyは開発中によく遭遇するバックグラウンドから与えられるkeyがappと異なる場合を解決することができます
class Person: Codable {
var name : String = ""
var age : Int = 0
enum CodingKeys : String, CodingKey {
case name = "name_a"
case age
}
}
//json
let JSONString = "{"name_a":"xiaoming","age":10}"
guard let jsonData = JSONString.data(using: .utf8) else {
return
}
let decoder = JSONDecoder()
guard let obj = try? decoder.decode(Person.self, from: jsonData) else {
return
}
print(obj.name) //xiaoming
また,一部のデータを受信する必要がない場合には,CodingKeyも扱うことができ,主にCodingKeysの列挙にこのkeyを書かないで済む.
class Person: Codable {
var name : String = ""
var age : Int = 0
var score : Double = 0.00
enum CodingKeys : String, CodingKey {
case name = "name_a"
case age
}
}
//json
let JSONString = "{"name_a":"xiaoming","age":10,"score":98.5}"
guard let jsonData = JSONString.data(using: .utf8) else {
return
}
let decoder = JSONDecoder()
guard let obj = try? decoder.decode(Person.self, from: jsonData) else {
return
}
print(obj.score) //0.00
パッヶージ
Codableのメカニズムに基づいて、プロジェクトに簡単にカプセル化することができます.現在よく見られるネットワークフレームワークでは、jsonデータを直接辞書に変換するため、辞書をjsonとjsonに変換する方法が追加されています.
//
// Custom.swift
//
//
// Created by qiuchengxiang@gmail.com on 2018/1/3.
// Copyright © 2018 Zillion Fortune. All rights reserved.
//
import Foundation
fileprivate enum MapError: Error {
case jsonToModelFail //json model
case jsonToDataFail //json data
case dictToJsonFail // json
case jsonToArrFail //json
case modelToJsonFail //model json
}
protocol Mappable: Codable {
func modelMapFinished()
mutating func structMapFinished()
}
extension Mappable {
func modelMapFinished() {}
mutating func structMapFinished() {}
//
func reflectToDict() -> [String:Any] {
let mirro = Mirror(reflecting: self)
var dict = [String:Any]()
for case let (key?, value) in mirro.children {
dict[key] = value
}
return dict
}
//
static func mapFromDict(_ dict : [String:Any], _ type:T.Type) throws -> T {
guard let JSONString = dict.toJSONString() else {
print(MapError.dictToJsonFail)
throw MapError.dictToJsonFail
}
guard let jsonData = JSONString.data(using: .utf8) else {
print(MapError.jsonToDataFail)
throw MapError.jsonToDataFail
}
let decoder = JSONDecoder()
if let obj = try? decoder.decode(type, from: jsonData) {
var vobj = obj
let mirro = Mirror(reflecting: vobj)
if mirro.displayStyle == Mirror.DisplayStyle.struct {
vobj.structMapFinished()
}
if mirro.displayStyle == Mirror.DisplayStyle.class {
vobj.modelMapFinished()
}
return vobj
}
print(MapError.jsonToModelFail)
throw MapError.jsonToModelFail
}
//JSON
static func mapFromJson(_ JSONString : String, _ type:T.Type) throws -> T {
guard let jsonData = JSONString.data(using: .utf8) else {
print(MapError.jsonToDataFail)
throw MapError.jsonToDataFail
}
let decoder = JSONDecoder()
if let obj = try? decoder.decode(type, from: jsonData) {
return obj
}
print(MapError.jsonToModelFail)
throw MapError.jsonToModelFail
}
// json
func toJSONString() throws -> String {
if let str = self.reflectToDict().toJSONString() {
return str
}
print(MapError.modelToJsonFail)
throw MapError.modelToJsonFail
}
}
extension Array {
func toJSONString() -> String? {
if (!JSONSerialization.isValidJSONObject(self)) {
print("dict json ")
return nil
}
if let newData : Data = try? JSONSerialization.data(withJSONObject: self, options: []) {
let JSONString = NSString(data:newData as Data,encoding: String.Encoding.utf8.rawValue)
return JSONString as String? ?? nil
}
print("dict json ")
return nil
}
func mapFromJson(_ type:[T].Type) throws -> Array {
guard let JSONString = self.toJSONString() else {
print(MapError.dictToJsonFail)
throw MapError.dictToJsonFail
}
guard let jsonData = JSONString.data(using: .utf8) else {
print(MapError.jsonToDataFail)
throw MapError.jsonToDataFail
}
let decoder = JSONDecoder()
if let obj = try? decoder.decode(type, from: jsonData) {
return obj
}
print(MapError.jsonToArrFail)
throw MapError.jsonToArrFail
}
}
extension Dictionary {
func toJSONString() -> String? {
if (!JSONSerialization.isValidJSONObject(self)) {
print("dict json ")
return nil
}
if let newData : Data = try? JSONSerialization.data(withJSONObject: self, options: []) {
let JSONString = NSString(data:newData as Data,encoding: String.Encoding.utf8.rawValue)
return JSONString as String? ?? nil
}
print("dict json ")
return nil
}
}
extension String {
func toDict() -> [String:Any]? {
guard let jsonData:Data = self.data(using: .utf8) else {
print("json dict ")
return nil
}
if let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) {
return dict as? [String : Any] ?? ["":""]
}
print("json dict ")
return nil
}
}
使用
enum BeerStyle : String, Codable {
case ipa
case stout
case kolsch
// ...
}
struct Beers: Mappable {
var arrs : [Beer]
var name : String
mutating func structMapFinished() {
name = "ngdgdfg"
}
struct Beer: Mappable {
var name: String = "fsdf"
var brewery: String = "fsdfsdf"
var style: BeerStyle = .ipa
var score: Double = 0.00
var p: Person?
enum CodingKeys : String, CodingKey {
case name = "name_a"
case brewery
case p
case score
}
class Person: Mappable {
var name : String = ""
var age : Int = 0
}
}
}
let dict1 = ["name_a":"nckjs","brewery":"gdfge","style":"stout","score":60.3,"p":["name":"jokh","age":10]] as [String : Any]
let dict2 = ["name_a":"nckjs","brewery":"gdfge","style":"stout","score":60.3,"p":["name":"jokh","age":10]] as [String : Any]
let dict3 = ["name_a":"nckjs","brewery":"gdfge","style":"stout","score":60.3,"p":["name":"jokh","age":10]] as [String : Any]
let arr = [dict1,dict2,dict3]
let dict4 = ["arrs" : arr, "name":"fgsdfs"] as [String : Any]
if let beers = try? Beers.mapFromDict(dict4, Beers.self) {
print(beers)
}
ここでmap完了後のコールバック法を追加したが,Codableの解析は,再オブジェクト属性のset法ではなく,OCのKVC原理とは異なるためである.したがって、いくつかの付与が完了した後の操作では、このコールバックメソッドを使用する必要があります.また、classとstructのタイプを区別し、対応する方法を選択することに注意する必要があります.
nullの処理
バックグラウンドで値ごとにnullが返される可能性があるというメッセージがあり、属性をオプションにしたくないのでnullの処理を増やし、nullに遭遇したら再init(from decoder:Decoder)throwsの方法が必要になる
class Person: Codable {
var name : String = ""
var age : Int = 0
init() {
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
age = try container.decodeNil(forKey: .age) ? 10 : try container.decode(Int.self, forKey: .age)
name = try container.decode(String.self, forKey: .name)
}
}
let p = Person()
let str = "{\"name\":\"fdfgdf\",\"age\":null}"
let jsonData = str.data(using: .utf8)
let decoder = JSONDecoder()
if let obj = try? decoder.decode(Person.self, from: jsonData!) {
print(obj.name,obj.age)
}else {
print(" ")
}
decodeNil(forKey:KeyedDecodingContainer.Key)throws->Bool解析時に対応する属性がnull値であるか否かを判断し、trueを返すならnullでないならfalseを返す
以上のパッケージは、swiftが強力な言語であるため、jsonデータのタイプがmodelプロパティのタイプに対応していることに注意してください.そうしないと、解析に失敗します.
参照先:http://www.cocoachina.com/swift/20170630/19691.html
demo:https://github.com/NickQCX/CXMap/blob/master/README.md