Fast conversion between JSON and model in Swift.
- Convert model to JSON with one line of code.(一行代码Model转JSON)
- Convert JSON to Model with one line of code.(一行代码JSON转Model)
- Archive\Unarchive object with one line of code.(一行代码实现常见数据的归档\解档)
pod 'KakaJSON', '~> 1.1.2' github "kakaopensource/KakaJSON" ~> 1.1.2To use Swift Package Manager, you should update to Xcode 11.
- Open your project.
- Click File tab
- Select Swift Packages
- Add Package Dependency, enter KakaJSON repo's URL
Or you can login Xcode with your GitHub account. just search KakaJSON.
- Coding
- JSON To Model_01_Basic Usage
- JSON To Model_02_Data Type
- JSON To Model_03_Key Mapping
- JSON To Model_04_Custom Value
- JSON To Model_05_Dynamic Model
- Model To JSON
// file path (can be String or URL)
let file = "/Users/mj/Desktop/test.data"
/****************** String ******************/
let string1 = "123"
// wrtite String to file
write(string1, to: file)
// read String from file
let string2 = read(String.self, from: file)
XCTAssert(string2 == string1)
// read Int from file
XCTAssert(read(Int.self, from: file) == 123)
/****************** Date ******************/
let date1 = Date(timeIntervalSince1970: 1565922866)
// wrtite Date to file
write(date1, to: file)
// read Date from file
let date2 = read(Date.self, from: file)
XCTAssert(date2 == date1)
// read Int from file
XCTAssert(read(Int.self, from: file) == 1565922866)
/****************** Array ******************/
let array1 = ["Jack", "Rose"]
// wrtite [String] to file
write(array1, to: file)
// read [String] from file
let array2 = read([String].self, from: file)
XCTAssert(array2 == array1)
// Also support Set\Dictionary
/****************** Model ******************/
struct Book: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Car: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Dog: Convertible {
var name: String = ""
var age: Int = 0
}
struct Person: Convertible {
var name: String = "Jack"
var car: Car? = Car(name: "Bently", price: 106.666)
var books: [Book]? = [
Book(name: "Fast C++", price: 666.6),
Book(name: "Data Structure And Algorithm", price: 666.6),
]
var dogs: [String: Dog]? = [
"dog0": Dog(name: "Wang", age: 5),
"dog1": Dog(name: "ErHa", age: 3),
]
}
// wrtite Person to file
write(Person(), to: file)
// read Person from file
let person = read(Person.self, from: file)
XCTAssert(person?.name == "Jack")
XCTAssert(person?.car?.name == "Bently")
XCTAssert(person?.car?.price == 106.666)
XCTAssert(person?.books?.count == 2)
XCTAssert(person?.dogs?.count == 2)
/****************** Model Array ******************/
struct Car: Convertible {
var name: String = ""
var price: Double = 0.0
}
let models1 = [
Car(name: "BMW", price: 100.0),
Car(name: "Audi", price: 70.0)
]
// wrtite [Car] to file
write(models1, to: file)
// read [Car] from file
let models2 = read([Car].self, from: file)
XCTAssert(models2?.count == models1.count)
XCTAssert(models2?[0].name == "BMW")
XCTAssert(models2?[0].price == 100.0)
XCTAssert(models2?[1].name == "Audi")
XCTAssert(models2?[1].price == 70.0)
/****************** Model Set ******************/
struct Car: Convertible, Hashable {
var name: String = ""
var price: Double = 0.0
}
let models1: Set<Car> = [
Car(name: "BMW", price: 100.0),
Car(name: "Audi", price: 70.0)
]
// wrtite Set<Car> to file
write(models1, to: file)
// read Set<Car> from file
let models2 = read(Set<Car>.self, from: file)!
XCTAssert(models2.count == models1.count)
for car in models2 {
XCTAssert(["BMW", "Audi"].contains(car.name))
XCTAssert([100.0, 70.0].contains(car.price))
}
/****************** Model Dictionary ******************/
struct Car: Convertible {
var name: String = ""
var price: Double = 0.0
}
let models1 = [
"car0": Car(name: "BMW", price: 100.0),
"car1": Car(name: "Audi", price: 70.0)
]
// wrtite [String: Car] to file
write(models1, to: file)
// read [String: Car] from file
let models2 = read([String: Car].self, from: file)
XCTAssert(models2?.count == models1.count)
let car0 = models2?["car0"]
XCTAssert(car0?.name == "BMW")
XCTAssert(car0?.price == 100.0)
let car1 = models2?["car1"]
XCTAssert(car1?.name == "Audi")
XCTAssert(car1?.price == 70.0)
struct Cat: Convertible {
var name: String = ""
var weight: Double = 0.0
}
// json can also be NSDictionary, NSMutableDictionary
let json: [String: Any] = [
"name": "Miaomiao",
"weight": 6.66
]
let cat1 = json.kj.model(Cat.self)
XCTAssert(cat1.name == "Miaomiao")
XCTAssert(cat1.weight == 6.66)
// you can call global function `model`
let cat2 = model(from: json, Cat.self)
// support type variable
var type: Convertible.Type = Cat.self
let cat3 = json.kj.model(type: type) as? Cat
let cat4 = model(from: json, type: type) as? Cat
class Cat: Convertible {
var weight: Double = 0.0
var name: String = ""
// The protocol `Convertible` required an init constructor
// for initializing an instance completely.
required init() {}
}
let json = ...
let cat = json.kj.model(Cat.self)
// a class inherit from NSObject
class Person: NSObject, Convertible {
var name: String = ""
var age: Int = 0
// must add `override` because NSObject has `init`
required override init() {}
}
let person = json.kj.model(Person.self)
struct Dog: Convertible {
var weight: Double = 0.0
var name: String = ""
// This struct don't need to implement init because compiler generates init for it
}
struct Pig: Convertible {
var weight: Double
var name: String
// This struct need to implement init to initialize all the stored properties.
init() {
name = ""
weight = 0.0
}
}
class Person: Convertible {
var name: String = ""
var age: Int = 0
required init() {}
}
class Student: Person {
var score: Int = 0
var no: String = ""
}
let json: [String: Any] = [
"name": "jack",
"age": 18,
"score": 98,
"no": "9527"
]
let student = json.kj.model(Student.self)
struct Cat: Convertible {
// let of integer type is very restricted in release mode
// please user `private(set) var` instead of `let`
private(set) var weight: Double = 0.0
let name: String = ""
}
let json = ...
let cat = json.kj.model(Cat.self)
struct Cat: Convertible {
var weight: Double = 0.0
var name: String = "xx"
var data: NSNull?
}
let json: [String: Any] = [
"name": NSNull(),
"weight": 6.6,
"data": NSNull()
]
let cat = json.kj.model(Cat.self)
// convert failed, keep default value
XCTAssert(cat.name == "xx")
XCTAssert(cat.weight == 6.6)
XCTAssert(cat.data == NSNull())
// jsonString can alse be NSString, NSMutableString
let jsonString = """
{
"name": "Miaomiao",
"weight": 6.66
}
"""
let cat1 = jsonString.kj.model(Cat.self)
let cat2 = model(from: jsonString, Cat.self)
var type: Convertible.Type = Cat.self
let cat3 = jsonString.kj.model(type: type) as? Cat
let cat4 = model(from: jsonString, type: type) as? Cat
// jsonData can alse be NSData, NSMutableData
let jsonData = """
{
"name": "Miaomiao",
"weight": 6.66
}
""".data(using: .utf8)!
let cat1 = jsonData.kj.model(Cat.self)
let cat2 = model(from: jsonData, Cat.self)
var type: Convertible.Type = Cat.self
let cat3 = jsonData.kj.model(type: type) as? Cat
let cat4 = model(from: jsonData, type: type) as? Cat
// let all the models comform to Convertible
struct Book: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Car: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Dog: Convertible {
var name: String = ""
var age: Int = 0
}
struct Person: Convertible {
var name: String = ""
var car: Car?
var books: [Book]?
var dogs: [String: Dog]?
}
let json: [String: Any] = [
"name": "Jack",
"car": ["name": "BMW7", "price": 105.5],
"books": [
["name": "Fast C++", "price": 666.6],
["name": "Data Structure And Algorithm", "price": 1666.6]
],
"dogs": [
"dog0": ["name": "Larry", "age": 5],
"dog1": ["name": "ErHa", "age": 2]
]
]
let person = json.kj.model(Person.self)
XCTAssert(person.car?.name == "BMW7")
XCTAssert(person.books?[1].name == "Data Structure And Algorithm")
XCTAssert(person.dogs?["dog0"]?.name == "Larry")
struct Book: Convertible, Hashable {
var name: String = ""
var price: Double = 0.0
}
struct Person: Convertible {
var name: String = ""
var books: Set<Book>?
}
let json: [String: Any] = [
"name": "Jack",
"books": [
["name": "Fast C++", "price": 666.6]
]
]
let person = json.kj.model(Person.self)
XCTAssert(person.name == "Jack")
XCTAssert(person.books?.count == 1)
let book = person.books?.randomElement()
XCTAssert(book?.name == "Fast C++")
XCTAssert(book?.price == 666.6)
struct Car: Convertible {
var name: String = ""
var price: Double = 0.0
}
class Dog: Convertible {
var name: String = ""
var age: Int = 0
required init() {}
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
struct Person: Convertible {
var name: String = ""
// KakaJSON will use your defaultValue instead of creating a new model
// KakaJSON will not creat a new model again if you already have a default model value
var car: Car = Car(name: "Bently", price: 106.5)
var dog: Dog = Dog(name: "Larry", age: 5)
}
let json: [String: Any] = [
"name": "Jake",
"car": ["price": 305.6],
"dog": ["name": "Wangwang"]
]
let person = json.kj.model(Person.self)
XCTAssert(person.name == "Jake")
// keep defaultValue
XCTAssert(person.car.name == "Bently")
// use value from json
XCTAssert(person.car.price == 305.6)
// use value from json
XCTAssert(person.dog.name == "Wangwang")
// keep defaultValue
XCTAssert(person.dog.age == 5)
class Person: Convertible {
var name: String = ""
var parent: Person?
required init() {}
}
let json: [String: Any] = [
"name": "Jack",
"parent": ["name": "Jim"]
]
let person = json.kj.model(Person.self)
XCTAssert(person.name == "Jack")
XCTAssert(person.parent?.name == "Jim")
struct NetResponse<Element>: Convertible {
let data: Element? = nil
let msg: String = ""
private(set) var code: Int = 0
}
struct User: Convertible {
let id: String = ""
let nickName: String = ""
}
struct Goods: Convertible {
private(set) var price: CGFloat = 0.0
let name: String = ""
}
let json1 = """
{
"data": {"nickName": "KaKa", "id": 213234234},
"msg": "Success",
"code" : 200
}
"""
let response1 = json1.kj.model(NetResponse<User>.self)
XCTAssert(response1?.msg == "Success")
XCTAssert(response1?.code == 200)
XCTAssert(response1?.data?.nickName == "KaKa")
XCTAssert(response1?.data?.id == "213234234")
let json2 = """
{
"data": [
{"price": "6199", "name": "iPhone XR"},
{"price": "8199", "name": "iPhone XS"},
{"price": "9099", "name": "iPhone Max"}
],
"msg": "Success",
"code" : 200
}
"""
let response2 = json2.kj.model(NetResponse<[Goods]>.self)
XCTAssert(response2?.msg == "Success")
XCTAssert(response2?.code == 200)
XCTAssert(response2?.data?.count == 3)
XCTAssert(response2?.data?[0].price == 6199)
XCTAssert(response2?.data?[0].name == "iPhone XR")
XCTAssert(response2?.data?[1].price == 8199)
XCTAssert(response2?.data?[1].name == "iPhone XS")
XCTAssert(response2?.data?[2].price == 9099)
XCTAssert(response2?.data?[2].name == "iPhone Max")
struct Car: Convertible {
var name: String = ""
var price: Double = 0.0
}
// json can also be NSArray, NSMutableArray
let json: [[String: Any]] = [
["name": "Benz", "price": 98.6],
["name": "Bently", "price": 305.7],
["name": "Audi", "price": 64.7]
]
let cars1 = json.kj.modelArray(Car.self)
XCTAssert(cars1[1].name == "Bently")
let cars2 = modelArray(from: json, Car.self)
var type: Convertible.Type = Car.self
let cars3 = json.kj.modelArray(type: type) as? [Car]
let cars4 = modelArray(from: json, type: type) as? [Car]
// jsonString -> Model Array
let jsonString = "...."
let cars5 = jsonString.kj.modelArray(Car.self)
let cars6 = modelArray(from: jsonString, Car.self)
let cars7 = jsonString.kj.modelArray(type: type) as? [Car]
let cars8 = modelArray(from: jsonString, type: type) as? [Car]
struct Book: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Person: Convertible {
var name: String = ""
var books: [String: [Book?]?]?
}
let name = "Jack"
let mobileBooks = [
(name: "iOS", price: 10.5),
(name: "Android", price: 8.5)
]
let serverBooks = [
(name: "Java", price: 20.5),
(name: "Go", price: 18.5)
]
let json: [String: Any] = [
"name": name,
"books": [
"mobile": [
["name": mobileBooks[0].name, "price": mobileBooks[0].price],
["name": mobileBooks[1].name, "price": mobileBooks[1].price]
],
"server": [
["name": serverBooks[0].name, "price": serverBooks[0].price],
["name": serverBooks[1].name, "price": serverBooks[1].price]
]
]
]
let person = json.kj.model(Person.self)
XCTAssert(person.name == name)
let books0 = person.books?["mobile"]
XCTAssert(books0??.count == mobileBooks.count)
for i in 0..<mobileBooks.count {
XCTAssert(books0??[i]?.name == mobileBooks[i].name);
XCTAssert(books0??[i]?.price == mobileBooks[i].price);
}
let books1 = person.books?["server"]
XCTAssert(books1??.count == serverBooks.count)
for i in 0..<serverBooks.count {
XCTAssert(books1??[i]?.name == serverBooks[i].name);
XCTAssert(books1??[i]?.price == serverBooks[i].price);
}
struct Cat: Convertible {
var name: String = ""
var weight: Double = 0.0
}
let json: [String: Any] = [
"name": "Miaomiao",
"weight": 6.66
]
var cat = Cat()
// fill a cat instance with json
// .kj_m is a mutable version of .kj
cat.kj_m.convert(json)
XCTAssert(cat.name == "Miaomiao")
XCTAssert(cat.weight == 6.66)
struct Car: Convertible {
var name: String = ""
var age: Int = 0
// call when will begin to convert from json to model
mutating func kj_willConvertToModel(from json: JSONObject) {
print("Car - kj_willConvertToModel")
}
// call when did finish converting from json to model
mutating func kj_didConvertToModel(from json: JSONObject) {
print("Car - kj_didConvertToModel")
}
}
let name = "Benz"
let age = 100
let car = ["name": name, "age": age].kj.model(Car.self)
// Car - kj_willConvertToModel
// Car - kj_didConvertToModel
XCTAssert(car.name == name)
XCTAssert(car.age == age)
/*************************************************************/
class Person: Convertible {
var name: String = ""
var age: Int = 0
required init() {}
func kj_willConvertToModel(from json: JSONObject) {
print("Person - kj_willConvertToModel")
}
func kj_didConvertToModel(from json: JSONObject) {
print("Person - kj_didConvertToModel")
}
}
class Student: Person {
var score: Int = 0
override func kj_willConvertToModel(from json: JSONObject) {
// call super's implementation if necessary
super.kj_willConvertToModel(from: json)
print("Student - kj_willConvertToModel")
}
override func kj_didConvertToModel(from json: JSONObject) {
// call super's implementation if necessary
super.kj_didConvertToModel(from: json)
print("Student - kj_didConvertToModel")
}
}
let name = "jack"
let age = 10
let score = 100
let student = ["name": name, "age": age, "score": score].kj.model(Student.self)
// Person - kj_willConvertToModel
// Student - kj_willConvertToModel
// Person - kj_didConvertToModel
// Student - kj_didConvertToModel
XCTAssert(student.name == name)
XCTAssert(student.age == age)
XCTAssert(student.score == score)
struct Student: Convertible {
var age1: Int8 = 6
var age2: Int16 = 0
var age3: Int32 = 0
var age4: Int64 = 0
var age5: UInt8 = 0
var age6: UInt16 = 0
var age7: UInt32 = 0
var age8: UInt64 = 0
var age9: UInt = 0
var age10: Int = 0
var age11: Int = 0
}
let json: [String: Any] = [
"age1": "suan8fa8",
"age2": "6suan8fa8",
"age3": "6",
"age4": 6.66,
"age5": NSNumber(value: 6.66),
"age6": Int32(6),
"age7": true,
"age8": "FALSE",
"age9": Decimal(6.66),
"age10": NSDecimalNumber(value: 6.66),
"age11": Date(timeIntervalSince1970: 1565922866)
]
let student = json.kj.model(Student.self)
// convert failed,keep defualt value
XCTAssert(student.age1 == 6)
XCTAssert(student.age2 == 6)
XCTAssert(student.age3 == 6)
XCTAssert(student.age4 == 6)
XCTAssert(student.age5 == 6)
XCTAssert(student.age6 == 6)
// true is 1,false is 0
XCTAssert(student.age7 == 1)
// "true"\"TRUE"\"YES"\"yes" is 1,"false"\"FALSE"\"NO"\"no" is 0
XCTAssert(student.age8 == 0)
XCTAssert(student.age9 == 6)
XCTAssert(student.age10 == 6)
XCTAssert(student.age11 == 1565922866)
struct Student: Convertible {
var height1: Float = 0.0
var height2: Float = 0.0
var height3: Float = 0.0
var height4: Float = 0.0
var height5: Float = 0.0
var height6: Float = 0.0
var height7: Float = 0.0
var height8: Float = 0.0
var height9: Float = 0.0
}
let json: [String: Any] = [
"height1": "6.66suan8fa8",
"height2": "0.12345678",
"height3": NSDecimalNumber(string: "0.12345678"),
"height4": Decimal(string: "0.12345678") as Any,
"height5": 666,
"height6": true,
"height7": "NO",
"height8": CGFloat(0.12345678),
"height9": Date(timeIntervalSince1970: 1565922866)
]
let student = json.kj.model(Student.self)
XCTAssert(student.height1 == 6.66)
XCTAssert(student.height2 == 0.12345678)
XCTAssert(student.height3 == 0.12345678)
XCTAssert(student.height4 == 0.12345678)
XCTAssert(student.height5 == 666.0)
// true is 1.0,false is 0.0
XCTAssert(student.height6 == 1.0)
// "true"\"TRUE"\"YES"\"yes" is 1.0,"false"\"FALSE"\"NO"\"no" is 0.0
XCTAssert(student.height7 == 0.0)
XCTAssert(student.height8 == 0.12345678)
XCTAssert(student.height9 == 1565922866)
struct Student: Convertible {
var height1: Double = 0.0
var height2: Double = 0.0
var height3: Double = 0.0
var height4: Double = 0.0
var height5: Double = 0.0
var height6: Double = 0.0
var height7: Double = 0.0
var height8: Double = 0.0
var height9: Double = 0.0
}
let json: [String: Any] = [
"height1": "6.66suan8fa8",
"height2": "0.1234567890123456",
"height3": NSDecimalNumber(string: "0.1234567890123456"),
"height4": Decimal(string: "0.1234567890123456") as Any,
"height5": 666,
"height6": true,
"height7": "NO",
"height8": CGFloat(0.1234567890123456),
"height9": Date(timeIntervalSince1970: 1565922866)
]
let student = json.kj.model(Student.self)
XCTAssert(student.height1 == 6.66)
XCTAssert(student.height2 == 0.1234567890123456)
XCTAssert(student.height3 == 0.1234567890123456)
XCTAssert(student.height4 == 0.1234567890123456)
XCTAssert(student.height5 == 666.0)
// true is 1.0,false is 0.0
XCTAssert(student.height6 == 1.0)
// "true"\"TRUE"\"YES"\"yes" is 1.0,"false"\"FALSE"\"NO"\"no" is 0.0
XCTAssert(student.height7 == 0.0)
XCTAssert(student.height8 == 0.1234567890123456)
XCTAssert(student.height9 == 1565922866)
struct Student: Convertible {
var height1: CGFloat = 0.0
var height2: CGFloat = 0.0
var height3: CGFloat = 0.0
var height4: CGFloat = 0.0
var height5: CGFloat = 0.0
var height6: CGFloat = 0.0
var height7: CGFloat = 0.0
var height8: CGFloat = 0.0
var height9: CGFloat = 0.0
}
let json: [String: Any] = [
"height1": "6.66suan8fa8",
"height2": "0.1234567890123456",
"height3": NSDecimalNumber(string: "0.1234567890123456"),
"height4": Decimal(string: "0.1234567890123456") as Any,
"height5": 666,
"height6": true,
"height7": "NO",
"height8": 0.1234567890123456,
"height9": Date(timeIntervalSince1970: 1565922866)
]
let student = json.kj.model(Student.self)
XCTAssert(student.height1 == 6.66)
XCTAssert(student.height2 == CGFloat(0.1234567890123456))
XCTAssert(student.height3 == CGFloat(0.1234567890123456))
XCTAssert(student.height4 == CGFloat(0.1234567890123456))
XCTAssert(student.height5 == 666.0)
XCTAssert(student.height6 == 1.0)
XCTAssert(student.height7 == 0.0)
XCTAssert(student.height8 == CGFloat(0.1234567890123456))
XCTAssert(student.height9 == CGFloat(1565922866))
struct Student: Convertible {
var rich1: Bool = false
var rich2: Bool = false
var rich3: Bool = false
var rich4: Bool = false
var rich5: Bool = false
var rich6: Bool = false
}
let json: [String: Any] = [
"rich1": 100,
"rich2": 0.0,
"rich3": "1",
"rich4": NSNumber(value: 0.666),
"rich5": "true",
"rich6": "NO"
]
let student = json.kj.model(Student.self)
// number 0 is false,not number 0 is true
XCTAssert(student.rich1 == true)
XCTAssert(student.rich2 == false)
XCTAssert(student.rich3 == true)
// 0.666 isn't 0,so true
XCTAssert(student.rich4 == true)
// "true"\"TRUE"\"YES"\"yes" is true
XCTAssert(student.rich5 == true)
// "false"\"FALSE"\"NO"\"no" is false
XCTAssert(student.rich6 == false)
// Support String, NSString, NSMutableString
struct Student: Convertible {
var name1: String = ""
var name2: String = ""
var name3: NSString = ""
var name4: NSString = ""
var name5: NSMutableString = ""
var name6: NSMutableString = ""
var name7: String = ""
var name8: String = ""
var name9: String = ""
}
let json: [String: Any] = [
"name1": 666,
"name2": NSMutableString(string: "777"),
"name3": [1,[2,3],"4"],
"name4": NSDecimalNumber(string: "0.123456789012345678901234567890123456789"),
"name5": 6.66,
"name6": false,
"name7": NSURL(fileURLWithPath: "/users/mj/desktop"),
"name8": URL(string: "http://www.520suanfa.com") as Any,
"name9": Date(timeIntervalSince1970: 1565922866)
]
let student = json.kj.model(Student.self)
XCTAssert(student.name1 == "666")
XCTAssert(student.name2 == "777")
// call array's description
XCTAssert(student.name3 == "[1, [2, 3], \"4\"]")
XCTAssert(student.name4 == "0.123456789012345678901234567890123456789")
XCTAssert(student.name5 == "6.66")
XCTAssert(student.name6 == "false")
XCTAssert(student.name7 == "file:///users/mj/desktop")
XCTAssert(student.name8 == "http://www.520suanfa.com")
XCTAssert(student.name9 == "1565922866")
struct Student: Convertible {
var money1: Decimal = 0
var money2: Decimal = 0
var money3: Decimal = 0
var money4: Decimal = 0
var money5: Decimal = 0
var money6: Decimal = 0
var money7: Decimal = 0
var money8: Decimal = 0
}
let json: [String: Any] = [
"money1": 0.1234567890123456,
"money2": true,
"money3": NSDecimalNumber(string: "0.123456789012345678901234567890123456789"),
"money4": "0.123456789012345678901234567890123456789",
"money5": 666,
"money6": "NO",
"money7": CGFloat(0.1234567890123456),
"money8": Date(timeIntervalSince1970: 1565922866)
]
let student = json.kj.model(Student.self)
XCTAssert(student.money1 == Decimal(string: "0.1234567890123456"))
XCTAssert(student.money2 == 1)
XCTAssert(student.money3 == Decimal(string: "0.123456789012345678901234567890123456789"))
XCTAssert(student.money4 == Decimal(string: "0.123456789012345678901234567890123456789"))
XCTAssert(student.money5 == 666)
XCTAssert(student.money6 == 0)
XCTAssert(student.money7 == Decimal(string: "0.1234567890123456"))
XCTAssert(student.money8 == Decimal(string: "1565922866"))
struct Student: Convertible {
var money1: NSDecimalNumber = 0
var money2: NSDecimalNumber = 0
var money3: NSDecimalNumber = 0
var money4: NSDecimalNumber = 0
var money5: NSDecimalNumber = 0
var money6: NSDecimalNumber = 0
var money7: NSDecimalNumber = 0
var money8: NSDecimalNumber = 0
}
let json: [String: Any] = [
"money1": 0.1234567890123456,
"money2": true,
"money3": Decimal(string: "0.123456789012345678901234567890123456789") as Any,
"money4": "0.123456789012345678901234567890123456789",
"money5": 666.0,
"money6": "NO",
"money7": CGFloat(0.1234567890123456),
"money8": Date(timeIntervalSince1970: 1565922866)
]
let student = json.kj.model(Student.self)
XCTAssert(student.money1 == NSDecimalNumber(string: "0.1234567890123456"))
XCTAssert(student.money2 == true)
XCTAssert(student.money2 == 1)
XCTAssert(student.money3 == NSDecimalNumber(string: "0.123456789012345678901234567890123456789"))
XCTAssert(student.money4 == NSDecimalNumber(string: "0.123456789012345678901234567890123456789"))
XCTAssert(student.money5 == 666)
XCTAssert(student.money6 == false)
XCTAssert(student.money6 == 0)
XCTAssert(student.money7 == NSDecimalNumber(string: "0.1234567890123456"))
XCTAssert(student.money8 == NSDecimalNumber(string: "1565922866"))
struct Student: Convertible {
var money1: NSNumber = 0
var money2: NSNumber = 0
var money3: NSNumber = 0
var money4: NSNumber = 0
var money5: NSNumber = 0
var money6: NSNumber = 0
var money7: NSNumber = 0
var money8: NSNumber = 0
}
let json: [String: Any] = [
"money1": 0.1234567890123456,
"money2": true,
"money3": Decimal(string: "0.1234567890123456") as Any,
"money4": "0.1234567890123456",
"money5": 666.0,
"money6": "NO",
"money7": CGFloat(0.1234567890123456),
"money8": Date(timeIntervalSince1970: 1565922866)
]
let student = json.kj.model(Student.self)
XCTAssert(student.money1 == NSNumber(value: 0.1234567890123456))
XCTAssert(student.money2 == true)
XCTAssert(student.money2 == 1)
XCTAssert(student.money2 == 1.0)
XCTAssert(student.money3 == NSNumber(value: 0.1234567890123456))
XCTAssert(student.money4 == NSNumber(value: 0.1234567890123456))
XCTAssert(student.money5 == 666)
XCTAssert(student.money5 == 666.0)
XCTAssert(student.money6 == false)
XCTAssert(student.money6 == 0)
XCTAssert(student.money6 == 0.0)
XCTAssert(student.money7 == NSNumber(value: longDouble))
XCTAssert(student.money8 == NSNumber(value: 1565922866))
// Support any number of ?
struct Student: Convertible {
var rich1: Bool = false
var rich2: Bool? = false
var rich3: Bool?? = false
var rich4: Bool??? = false
var rich5: Bool???? = false
var rich6: Bool????? = false
}
let rich1: Int????? = 100
let rich2: Double???? = 0.0
let rich3: String??? = "0"
let rich4: NSNumber?? = NSNumber(value: 0.666)
let rich5: String? = "true"
let rich6: String = "NO"
let json: [String: Any] = [
"rich1": rich1 as Any,
"rich2": rich2 as Any,
"rich3": rich3 as Any,
"rich4": rich4 as Any,
"rich5": rich5 as Any,
"rich6": rich6
]
let student = json.kj.model(Student.self)
XCTAssert(student.rich1 == true)
XCTAssert(student.rich2 == false)
XCTAssert(student.rich3 == false)
XCTAssert(student.rich4 == true)
XCTAssert(student.rich5 == true)
XCTAssert(student.rich6 == false)
// Support URL, NSURL
struct Student: Convertible {
var url1: NSURL?
var url2: NSURL?
var url3: URL?
var url4: URL?
}
let url = "http://520suanfa.com/红黑树"
let encodedUrl = "http://520suanfa.com/%E7%BA%A2%E9%BB%91%E6%A0%91"
let json: [String: Any] = [
"url1": url,
"url2": URL(string: encodedUrl) as Any,
"url3": url,
"url4": NSURL(string: encodedUrl) as Any
]
let student = json.kj.model(Student.self)
XCTAssert(student.url1?.absoluteString == encodedUrl)
XCTAssert(student.url2?.absoluteString == encodedUrl)
XCTAssert(student.url3?.absoluteString == encodedUrl)
XCTAssert(student.url4?.absoluteString == encodedUrl)
// Support NSData, Data
struct Student: Convertible {
var data1: NSData?
var data2: NSData?
var data3: Data?
var data4: Data?
var data5: NSMutableData?
var data6: NSMutableData?
}
let utf8 = String.Encoding.utf8
let str = "RedBlackTree"
let data = str.data(using: utf8)!
let json: [String: Any] = [
"data1": str,
"data2": data,
"data3": str,
"data4": NSMutableData(data: data),
"data5": str,
"data6": data
]
let student = json.kj.model(Student.self)
XCTAssert(String(data: (student.data1)! as Data, encoding: utf8) == str)
XCTAssert(String(data: (student.data2)! as Data, encoding: utf8) == str)
XCTAssert(String(data: (student.data3)!, encoding: utf8) == str)
XCTAssert(String(data: (student.data4)!, encoding: utf8) == str)
XCTAssert(String(data: (student.data5)! as Data, encoding: utf8) == str)
XCTAssert(String(data: (student.data6)! as Data, encoding: utf8) == str)
// Support Date, NSDate
struct Student: Convertible {
var date1: NSDate?
var date2: NSDate?
var date3: Date?
var date4: Date?
var date5: Date?
var date6: Date?
var date7: Date?
}
let milliseconds: TimeInterval = 1565922866
let json: [String: Any] = [
"date1": milliseconds,
"date2": Date(timeIntervalSince1970: milliseconds),
"date3": milliseconds,
"date4": NSDate(timeIntervalSince1970: milliseconds),
"date5": "\(milliseconds)",
"date6": NSDecimalNumber(string: "\(milliseconds)"),
"date7": Decimal(string: "\(milliseconds)") as Any
]
let student = json.kj.model(Student.self)
XCTAssert(student.date1?.timeIntervalSince1970 == milliseconds)
XCTAssert(student.date2?.timeIntervalSince1970 == milliseconds)
XCTAssert(student.date3?.timeIntervalSince1970 == milliseconds)
XCTAssert(student.date4?.timeIntervalSince1970 == milliseconds)
XCTAssert(student.date5?.timeIntervalSince1970 == milliseconds)
XCTAssert(student.date6?.timeIntervalSince1970 == milliseconds)
XCTAssert(student.date7?.timeIntervalSince1970 == milliseconds)
// let enum with rawValue conform to ConvertibleEnum
// String RawValue
enum Grade: String, ConvertibleEnum {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
struct Student: Convertible {
var grade1: Grade = .perfect
var grade2: Grade = .perfect
}
let json: [String: Any] = [
"grade1": "C",
"grade2": "D"
]
let student = json.kj.model(Student.self)
XCTAssert(student.grade1 == .good)
XCTAssert(student.grade2 == .bad)
// Double RawValue
enum Grade2: Double, ConvertibleEnum {
case perfect = 8.88
case great = 7.77
case good = 6.66
case bad = 5.55
}
struct Student2: Convertible {
var grade1: Grade2 = .perfect
var grade2: Grade2 = .perfect
var grade3: Grade2 = .perfect
var grade4: Grade2 = .perfect
}
let json2: [String: Any] = [
"grade1": "5.55kaka",
"grade2": 6.66,
"grade3": NSNumber(value: 7.77),
"grade4": NSDecimalNumber(string: "8.88")
]
let student2 = json2.kj.model(Student2.self)
XCTAssert(student2?.grade1 == .bad)
XCTAssert(student2?.grade2 == .good)
XCTAssert(student2?.grade3 == .great)
XCTAssert(student2?.grade4 == .perfect)
enum Grade: String, ConvertibleEnum {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
struct Student: Convertible {
var name: String?
var grades: [Grade]?
}
let json: [String: Any] = [
"name": "Jack",
"grades": ["D", "B"]
]
let stu = json.kj.model(Student.self)
XCTAssert(stu.name == "Jack")
XCTAssert(stu.grades?[0] == .bad)
XCTAssert(stu.grades?[1] == .great)
enum Grade: String, ConvertibleEnum {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
struct Student: Convertible {
var name: String?
var grades: [String: Grade]?
}
let json: [String: Any] = [
"name": "Jack",
"grades": ["2019": "D", "2020": "B"]
]
let stu = json.kj.model(Student.self)
XCTAssert(stu.name == "Jack")
XCTAssert(stu.grades?["2019"] == .bad)
XCTAssert(stu.grades?["2020"] == .great)
enum Grade: String, ConvertibleEnum {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
struct Student: Convertible {
var name: String?
var grades: [String: [Grade?]]?
}
let json: [String: Any] = [
"name": "Jack",
"grades": ["2019": ["A", "B"], "2020": ["C", "D"]]
]
let stu = json.kj.model(Student.self)
XCTAssert(stu.name == "Jack")
XCTAssert(stu.grades?["2019"]?[0] == .perfect)
XCTAssert(stu.grades?["2019"]?[1] == .great)
XCTAssert(stu.grades?["2020"]?[0] == .good)
XCTAssert(stu.grades?["2020"]?[1] == .bad)
// Support conversion between Array\NSArray\NSMutableArray and Set\NSSet\NSMutableSet
struct Person: Convertible {
var array1: [Int]?
var array2: NSArray?
var array3: NSMutableArray?
var array4: [Int]?
var array5: NSArray?
var array6: NSMutableArray?
}
let array = [1, 2, 3]
let json: [String: Any] = [
"array1": NSMutableArray(array: array),
"array2": array,
"array3": array,
"array4": NSMutableSet(array: array),
"array5": NSSet(array: array),
"array6": Set(array),
]
let person = json.kj.model(Person.self)
XCTAssert(person.array1 == array)
XCTAssert(person.array2 == array as NSArray)
XCTAssert(person.array3 == NSMutableArray(array: array))
for i in array {
XCTAssert(person.array4?.contains(i) == true)
XCTAssert(person.array5?.contains(i) == true)
XCTAssert(person.array6?.contains(i) == true)
}
// Support conversion between Set\NSSet\NSMutableSet and Array\NSArray\NSMutableArray
struct Person: Convertible {
var set1: Set<Int>?
var set2: NSSet?
var set3: NSMutableSet?
var set4: Set<Int>?
var set5: NSSet?
var set6: NSMutableSet?
}
let array = [1, 2, 3]
let json: [String: Any] = [
"set1": NSMutableSet(array: array),
"set2": Set(array),
"set3": Set(array),
"set4": NSMutableArray(array: array),
"set5": array,
"set6": array
]
let person = json.kj.model(Person.self)
for i in array {
XCTAssert(person.set1?.contains(i) == true)
XCTAssert(person.set2?.contains(i) == true)
XCTAssert(person.set3?.contains(i) == true)
XCTAssert(person.set4?.contains(i) == true)
XCTAssert(person.set5?.contains(i) == true)
XCTAssert(person.set6?.contains(i) == true)
}
// Support conversion between Dictionary, NSDictionary and NSMutableDictionary
struct Person: Convertible {
var dict1: [String: Any]?
var dict2: NSDictionary?
var dict3: NSMutableDictionary?
}
let dict = ["no1": 100, "no2": 200]
let json: [String: Any] = [
"dict1": NSMutableDictionary(dictionary: dict),
"dict2": dict,
"dict3": dict
]
let person = json.kj.model(Person.self)
for (k, v) in dict {
XCTAssert(person.dict1?[k] as? Int == v)
XCTAssert(person.dict2?[k] as? Int == v)
XCTAssert(person.dict3?[k] as? Int == v)
}
struct Person: Convertible {
var nickName: String = ""
var mostFavoriteNumber: Int = 0
var birthday: String = ""
func kj_modelKey(from property: Property) -> ModelPropertyKey {
switch property.name {
// `nickName` -> `nick_name`
case "nickName": return "nick_name"
// `mostFavoriteNumber` -> `most_favorite_number`
case "mostFavoriteNumber": return "most_favorite_number"
default: return property.name
}
}
}
let nick_name = "ErHa"
let most_favorite_number = 666
let birthday = "2011-10-12"
let json: [String: Any] = [
"nick_name": nick_name,
"most_favorite_number": most_favorite_number,
"birthday": birthday
]
let student = json.kj.model(Person.self)
XCTAssert(student.nickName == nick_name)
XCTAssert(student.mostFavoriteNumber == most_favorite_number)
XCTAssert(student.birthday == birthday)
struct Person: Convertible {
var nickName: String = ""
var mostFavoriteNumber: Int = 0
var birthday: String = ""
func kj_modelKey(from property: Property) -> ModelPropertyKey {
// `nickName` -> `nick_name`
return property.name.kj.underlineCased()
}
}
let nick_name = "ErHa"
let most_favorite_number = 666
let birthday = "2011-10-12"
let json: [String: Any] = [
"nick_name": nick_name,
"most_favorite_number": most_favorite_number,
"birthday": birthday
]
let student = json.kj.model(Person.self)
XCTAssert(student.nickName == nick_name)
XCTAssert(student.mostFavoriteNumber == most_favorite_number)
XCTAssert(student.birthday == birthday)
struct Person: Convertible {
var nick_name: String = ""
var most_favorite_number: Int = 0
var birthday: String = ""
func kj_modelKey(from property: Property) -> ModelPropertyKey {
// `nick_name` -> `nickName`
return property.name.kj.camelCased()
}
}
let nickName = "ErHa"
let mostFavoriteNumber = 666
let birthday = "2011-10-12"
let json: [String: Any] = [
"nickName": nickName,
"mostFavoriteNumber": mostFavoriteNumber,
"birthday": birthday
]
let student = json.kj.model(Person.self)
XCTAssert(student.nick_name == nickName)
XCTAssert(student.most_favorite_number == mostFavoriteNumber)
XCTAssert(student.birthday == birthday)
class Person: Convertible {
var nickName: String = ""
required init() {}
func kj_modelKey(from property: Property) -> ModelPropertyKey {
// `nickName` -> `nick_ame`
return property.name.kj.underlineCased()
}
}
class Student: Person {
var mathScore: Int = 0
// `mathScore` -> `math_score`
}
let nick_ame = "Jack"
let math_score = 96
let json: [String: Any] = ["nick_name": nick_ame, "math_score": math_score]
let person = json.kj.model(Person.self)
XCTAssert(person.nickName == nick_ame)
let student = json.kj.model(Student.self)
XCTAssert(student.nickName == nick_ame)
XCTAssert(student.mathScore == math_score)
class Person: Convertible {
var name: String = ""
required init() {}
func kj_modelKey(from property: Property) -> ModelPropertyKey {
// `name` -> `_name_`
return property.name == "name" ? "_name_" : property.name
}
}
class Student: Person {
var score: Int = 0
override func kj_modelKey(from property: Property) -> ModelPropertyKey {
// `score` -> `_score_`,`name` -> `_name_`
return property.name == "score" ? "_score_" : super.kj_modelKey(from: property)
}
}
let name = "Jack"
let score = 96
let json: [String: Any] = ["_name_": name, "_score_": score]
let person = json.kj.model(Person.self)
XCTAssert(person.name == name)
let student = json.kj.model(Student.self)
XCTAssert(student.name == name)
XCTAssert(student.score == score)
class Person: Convertible {
var name: String = ""
required init() {}
func kj_modelKey(from property: Property) -> ModelPropertyKey {
// `name` -> `_name_`
return property.name == "name" ? "_name_" : property.name
}
}
class Student: Person {
var score: Int = 0
override func kj_modelKey(from property: Property) -> ModelPropertyKey {
// `score` -> `_score_`,`name` -> `name`
return property.name == "score" ? "_score_" : property.name
}
}
let personName = "Jack"
let person = ["_name_": personName].kj.model(Person.self)
XCTAssert(person.name == personName)
let studentName = "Rose"
let studentScore = 96
let student = ["name": studentName,
"_score_": studentScore].kj.model(Student.self)
XCTAssert(student.name == studentName)
XCTAssert(student.score == studentScore)
// Set global config once, effect on any type
ConvertibleConfig.setModelKey { property in
property.name.kj.underlineCased()
}
// ConvertibleConfig.setModelKey { $0.name.kj.underlineCased() }
class Person: Convertible {
var nickName: String = ""
required init() {}
}
class Student: Person {
var mathScore: Int = 0
}
struct Car: Convertible {
var maxSpeed: Double = 0.0
var name: String = ""
}
let nick_ame = "Jack"
let math_score = 96
let json: [String: Any] = ["nick_name": nick_ame, "math_score": math_score]
let person = json.kj.model(Person.self)
XCTAssert(person.nickName == nick_ame)
let student = json.kj.model(Student.self)
XCTAssert(student.nickName == nick_ame)
XCTAssert(student.mathScore == math_score)
let max_speed = 250.0
let name = "Bently"
let car = ["max_speed": max_speed, "name": name].kj.model(Car.self)
XCTAssert(car.maxSpeed == max_speed)
XCTAssert(car.name == name)
// Set config for Person, Car
// It effects on Student because Person is Student's superclass
ConvertibleConfig.setModelKey(for: [Person.self, Car.self]) {
property in
property.name.kj.underlineCased()
}
class Person: Convertible {
var nickName: String = ""
required init() {}
}
class Student: Person {
var mathScore: Int = 0
}
struct Car: Convertible {
var maxSpeed: Double = 0.0
var name: String = ""
}
let nick_ame = "Jack"
let math_score = 96
let json: [String: Any] = ["nick_name": nick_ame, "math_score": math_score]
let person = json.kj.model(Person.self)
XCTAssert(person.nickName == nick_ame)
let student = json.kj.model(Student.self)
XCTAssert(student.nickName == nick_ame)
XCTAssert(student.mathScore == math_score)
let max_speed = 250.0
let name = "Bently"
let car = ["max_speed": max_speed, "name": name].kj.model(Car.self)
XCTAssert(car.maxSpeed == max_speed)
XCTAssert(car.name == name)
// Global config
ConvertibleConfig.setModelKey { property in
property.name.kj.underlineCased()
}
// Config of Person
ConvertibleConfig.setModelKey(for: Person.self) { property in
// `name` -> `_name_`
property.name == "name" ? "_name_" : property.name
}
// Config of Student
ConvertibleConfig.setModelKey(for: Student.self) { property in
// `score` -> `_score_`,`name` -> `name`
property.name == "score" ? "_score_" : property.name
}
class Person: Convertible {
var name: String = ""
required init() {}
}
class Student: Person {
var score: Int = 0
}
struct Car: Convertible {
var maxSpeed: Double = 0.0
var name: String = ""
}
let personName = "Jack"
let person = ["_name_": personName].kj.model(Person.self)
XCTAssert(person.name == personName)
let studentName = "Rose"
let studentScore = 96
let student = ["name": studentName,
"_score_": studentScore].kj.model(Student.self)
XCTAssert(student.name == studentName)
XCTAssert(student.score == studentScore)
let max_speed = 250.0
let name = "Bently"
let car = ["max_speed": max_speed, "name": name].kj.model(Car.self)
XCTAssert(car.maxSpeed == max_speed)
XCTAssert(car.name == name)
// Global config
ConvertibleConfig.setModelKey { property in
property.name.kj.underlineCased()
}
// Config of Person
ConvertibleConfig.setModelKey(for: Person.self) { property in
// `name` -> `_name_`
property.name == "name" ? "_name_" : property.name
}
// Config of Student
ConvertibleConfig.setModelKey(for: Student.self) { property in
// `score` -> `_score_`,`name` -> `name`
property.name == "score" ? "_score_" : property.name
}
class Person: Convertible {
var name: String = ""
required init() {}
func kj_modelKey(from property: Property) -> ModelPropertyKey {
// use ConvertibleConfig to get the config of Person
// `name` -> `_name_`
return ConvertibleConfig.modelKey(from: property, Person.self)
}
}
class Student: Person {
var score: Int = 0
override func kj_modelKey(from property: Property) -> ModelPropertyKey {
// `score` -> `score`,`name` -> `name`
return property.name
}
}
struct Car: Convertible {
var maxSpeed: Double = 0.0
var name: String = ""
func kj_modelKey(from property: Property) -> ModelPropertyKey {
// use ConvertibleConfig to get the global config
// `maxSpeed` -> `max_speed`
// `name` -> `name`
return ConvertibleConfig.modelKey(from: property)
}
}
/*
If there are many settings of modelKey, the rule is (e.g. Student)
1. use Student's kj_modelKey firstly
2. if 1 dosen't exist, use ConvertibleConfig of Student
3. if 1\2 dosen't exist, use ConvertibleConfig of Student's superclass
4. if 1\2\3 dosen't exist, use ConvertibleConfig of Student's superclass's superclass...
5. if 1\2\3\4 dosen't exist, use gloabal ConvertibleConfig
*/
// Person, Student, Car all have kj_modelKey, so use kj_modelKey firstly
let personName = "Jack"
let person = ["_name_": personName].kj.model(Person.self)
XCTAssert(person.name == personName)
let studentName = "Rose"
let studentScore = 96
let student = ["name": studentName,
"score": studentScore].kj.model(Student.self)
XCTAssert(student.name == studentName)
XCTAssert(student.score == studentScore)
let max_speed = 250.0
let name = "Bently"
let car = ["max_speed": max_speed, "name": name].kj.model(Car.self)
XCTAssert(car.maxSpeed == max_speed)
XCTAssert(car.name == name)
struct Toy: Convertible {
var price: Double = 0.0
var name: String = ""
}
struct Dog: Convertible {
var name: String = ""
var age: Int = 0
var nickName: String?
var toy: Toy?
func kj_modelKey(from property: Property) -> ModelPropertyKey {
switch property.name {
// toy -> dog["toy"]
case "toy": return "dog.toy"
// name -> data[1]["dog"]["name"]
case "name": return "data.1.dog.name"
// try every mapping of array orderly until success
// 1. nickName -> nickName
// 2. nickName -> nick_name
// 3. nickName -> dog["nickName"]
// 4. nickName -> dog["nick_name"]
case "nickName": return ["nickName", "nick_name", "dog.nickName", "dog.nick_name"]
default: return property.name
}
}
}
let name = "Larry"
let age = 5
let nickName1 = "Jake1"
let nickName2 = "Jake2"
let nickName3 = "Jake3"
let nickName4 = "Jake4"
let toy = (name: "Bobbi", price: 20.5)
let json: [String: Any] = [
"data": [10, ["dog" : ["name": name]]],
"age": age,
"nickName": nickName1,
"nick_name": nickName2,
"dog": [
"nickName": nickName3,
"nick_name": nickName4,
"toy": ["name": toy.name, "price": toy.price]
]
]
let dog = json.kj.model(Dog.self)
XCTAssert(dog.name == name)
XCTAssert(dog.age == age)
XCTAssert(dog.nickName == nickName1)
XCTAssert(dog.toy?.name == toy.name)
XCTAssert(dog.toy?.price == toy.price)
/*-------------------------------------------------*/
struct Team: Convertible {
var name: String?
var captainName: String?
func kj_modelKey(from property: Property) -> ModelPropertyKey {
switch property.name {
case "captainName": return "captain.name"
default: return property.name
}
}
}
let teamName = "V"
let captainName = "Quentin"
let json: [String: Any] = [
"name": teamName,
"captain.name": captainName,
]
let team = json.kj.model(Team.self)
XCTAssert(team.name == teamName)
XCTAssert(team.captainName == captainName)
/*-------------------------------------------------*/
struct Model: Convertible {
var valueA: String?
var valueB: String?
func kj_modelKey(from property: Property) -> ModelPropertyKey {
switch property.name {
case "valueA": return "a.0.a"
case "valueB": return "b.0.b.0.b"
default: return property.name
}
}
}
let json: [String: Any] = [
"a": [ "l", "u", "o" ],
"b": [
[ "b": [ "x", "i", "u" ] ]
]
]
let model = json.kj.model(Model.self)
XCTAssert(model.valueA == "l")
XCTAssert(model.valueB == "x")
private let date1Fmt: DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = "yyyy-MM-dd"
return fmt
}()
private let date2Fmt: DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
return fmt
}()
struct Student: Convertible {
var date1: Date?
var date2: NSDate?
func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? {
switch property.name {
case "date1": return (jsonValue as? String).flatMap(date1Fmt.date)
case "date2": return (jsonValue as? String).flatMap(date2Fmt.date)
default: return jsonValue
}
}
}
let date1 = "2008-09-09"
let date2 = "2011-11-12 14:20:30.888"
let json: [String: Any] = [
"date1": date1,
"date2": date2
]
let student = json.kj.model(Student.self)
XCTAssert(student.date1.flatMap(date1Fmt.string) == date1)
XCTAssert(student.date2.flatMap(date2Fmt.string) == date2)
struct Person: Convertible {
var name: String = ""
var pet: Any?
func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? {
if property.name != "pet" { return jsonValue }
return (jsonValue as? [String: Any])?.kj.model(Dog.self)
}
}
struct Dog: Convertible {
var name: String = ""
var weight: Double = 0.0
}
let json: [String: Any] = [
"name": "Jack",
"pet": ["name": "Wang", "weight": 109.5]
]
let person = json.kj.model(Person.self)
XCTAssert(person.name == "Jack")
let pet = person.pet as? Dog
XCTAssert(pet?.name == "Wang")
XCTAssert(pet?.weight == 109.5)
/*-------------------------------------------------*/
class Book: Convertible {
var name: String = ""
var price: Double = 0.0
required init() {}
}
struct Person: Convertible {
var name: String = ""
// [AnyObject]、[Convertible]、NSArray、NSMutableArray
var books: [Any]?
func kj_modelValue(from jsonValue: Any?,
_ property: Property) -> Any? {
if property.name != "books" { return jsonValue }
// if books is `NSMutableArray`, neet convert `Array` to `NSMutableArray`
// because `Array` to `NSMutableArray` is not a bridging conversion
return (jsonValue as? [Any])?.kj.modelArray(Book.self)
}
}
let name = "Jack"
let books = [
(name: "Fast C++", price: 666),
(name: "Data Structure And Algorithm", price: 1666)
]
let json: [String: Any] = [
"name": name,
"books": [
["name": books[0].name, "price": books[0].price],
["name": books[1].name, "price": books[1].price]
]
]
let person = json.kj.model(Person.self)
XCTAssert(person.name == name)
XCTAssert(person.books?.count == books.count)
let book0 = person.books?[0] as? Book
XCTAssert(book0?.name == books[0].name)
XCTAssert(book0?.price == Double(books[0].price))
let book1 = person.books?[1] as? Book
XCTAssert(book1?.name == books[1].name)
XCTAssert(book1?.price == Double(books[1].price))
struct Student: Convertible {
var age: Int = 0
var name: String = ""
func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? {
switch property.name {
case "age": return (jsonValue as? Int).flatMap { $0 + 5 }
case "name": return (jsonValue as? String).flatMap { "kj_" + $0 }
default: return jsonValue
}
}
}
let json: [String: Any] = [
"age": 10,
"name": "Jack"
]
let student = json.kj.model(Student.self)
XCTAssert(student.age == 15)
XCTAssert(student.name == "kj_Jack")
struct Student: Convertible {
var age: Int = 0
var name: String = ""
mutating func kj_didConvertToModel(from json: JSONObject) {
age += 5
name = "kj_" + name
}
}
let json: [String: Any] = [
"age": 10,
"name": "Jack"
]
let student = json.kj.model(Student.self)
XCTAssert(student.age == 15)
XCTAssert(student.name == "kj_Jack")
struct Book: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Car: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Pig: Convertible {
var name: String = ""
var height: Double = 0.0
}
struct Dog: Convertible {
var name: String = ""
var weight: Double = 0.0
}
struct Person: Convertible {
var name: String = ""
var pet: Any?
// toys can also be NSArray, NSMutableArray
var toys: [Any]?
// foods can also be NSDictionary, NSMutableDictionary
var foods: [String: Any]?
func kj_modelType(from jsonValue: Any?, _ property: Property) -> Convertible.Type? {
switch property.name {
case "toys": return Car.self
case "foods": return Book.self
case "pet":
if let pet = jsonValue as? [String: Any],
let _ = pet["height"] {
return Pig.self
}
return Dog.self
default: return nil
}
}
}
let name = "Jack"
let dog = (name: "Wang", weight: 109.5)
let pig = (name: "Keke", height: 1.55)
let books = [
(name: "Fast C++", price: 666.0),
(name: "Data Structure And Algorithm", price: 1666.0)
]
let cars = [
(name: "Benz", price: 100.5),
(name: "Bently", price: 300.6)
]
let json: [String: Any] = [
"name": name,
"pet": ["name": dog.name, "weight": dog.weight],
// "pet": ["name": pig.name, "height": pig.height],
"toys": [
["name": cars[0].name, "price": cars[0].price],
["name": cars[1].name, "price": cars[1].price]
],
"foods": [
"food0": ["name": books[0].name, "price": books[0].price],
"food1": ["name": books[1].name, "price": books[1].price]
]
]
let person = json.kj.model(Person.self)
XCTAssert(person.name == name)
if let pet = person.pet as? Dog {
XCTAssert(pet.name == dog.name)
XCTAssert(pet.weight == dog.weight)
} else if let pet = person.pet as? Pig {
XCTAssert(pet.name == pig.name)
XCTAssert(pet.height == pig.height)
}
let toy0 = person.toys?[0] as? Car
XCTAssert(toy0?.name == cars[0].name)
XCTAssert(toy0?.price == cars[0].price)
let toy1 = person.toys?[1] as? Car
XCTAssert(toy1?.name == cars[1].name)
XCTAssert(toy1?.price == cars[1].price)
let food0 = person.foods?["food0"] as? Book
XCTAssert(food0?.name == books[0].name)
XCTAssert(food0?.price == books[0].price)
let food1 = person.foods?["food1"] as? Book
XCTAssert(food1?.name == books[1].name)
XCTAssert(food1?.price == books[1].price)
struct Car: Convertible {
var name: String = "Bently"
var new: Bool = true
var age: Int = 10
var area: Float = 0.12345678
var weight: Double = 0.1234567890123456
var height: Decimal = 0.123456789012345678901234567890123456789
var price: NSDecimalNumber = NSDecimalNumber(string: "0.123456789012345678901234567890123456789")
var minSpeed: Double = 66.66
var maxSpeed: NSNumber = 77.77
var capacity: CGFloat = 88.88
var birthday: Date = Date(timeIntervalSince1970: 1565922866)
var url: URL? = URL(string: "http://520suanfa.com")
}
let car = Car()
// car -> JSON
let json1 = car.kj.JSONObject()
// global function `JSONObject(from:)`
let json2 = JSONObject(from: car)
// car -> JSONString
let jsonString1 = car.kj.JSONString()
// global function `JSONString(from:)`
let jsonString2 = JSONString(from: car)
/* {"birthday":1565922866,"new":true,"height":0.123456789012345678901234567890123456789,
"weight":0.1234567890123456,"minSpeed":66.66,
"price":0.123456789012345678901234567890123456789,"age":10,
"name":"Bently","area":0.12345678,"maxSpeed":77.77,
"capacity":88.88,"url":"http:\/\/520suanfa.com"} */
// get prettyPrinted JSONString
let jsonString3 = car.kj.JSONString(prettyPrinted: true)
let jsonString4 = JSONString(from: car, prettyPrinted: true)
/*
{
"height" : 0.123456789012345678901234567890123456789,
"weight" : 0.1234567890123456,
"minSpeed" : 66.66,
"new" : true,
"maxSpeed" : 77.77,
"age" : 10,
"capacity" : 88.88,
"birthday" : 1565922866,
"name" : "Bently",
"price" : 0.123456789012345678901234567890123456789,
"area" : 0.12345678,
"url" : "http:\/\/520suanfa.com"
}
*/
struct Student: Convertible, Equatable {
var op1: Int? = 10
var op2: Double?? = 66.66
var op3: Float??? = 77.77
var op4: String???? = "Jack"
var op5: Bool????? = true
// op6 can alse be NSArray\Set<CGFloat>\NSSet\NSMutableArray\NSMutableSet
var op6: [CGFloat]?????? = [44.44, 55.55]
}
let jsonString = Student().kj.JSONString()
/*
{
"op1" : 10,
"op4" : "Jack",
"op2" : 66.66,
"op5" : true,
"op6" : [
44.44,
55.55
],
"op3" : 77.77
}
*/
// A enum with rawValue who conforms to ConvertibleEnum
enum Grade: String, ConvertibleEnum {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
struct Student: Convertible {
var grade1: Grade = .great
var grade2: Grade = .bad
}
// put rawValue into the jsonString
let jsonString = Student().kj.JSONString()
/* {"grade2":"D","grade1":"B"} */
struct Book: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Car: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Dog: Convertible {
var name: String = ""
var age: Int = 0
}
struct Person: Convertible {
var name: String = "Jack"
var car: Car? = Car(name: "Bently", price: 106.666)
var books: [Book]? = [
Book(name: "Fast C++", price: 666.6),
Book(name: "Data Structure And Algorithm", price: 666.6),
]
var dogs: [String: Dog]? = [
"dog0": Dog(name: "Wang", age: 5),
"dog1": Dog(name: "ErHa", age: 3),
]
}
let jsonString = Person().kj.JSONString()
/*
{
"dogs" : {
"dog0" : {
"name" : "Wang",
"age" : 5
},
"dog1" : {
"name" : "ErHa",
"age" : 3
}
},
"books" : [
{
"price" : 666.6,
"name" : "Fast C++"
},
{
"name" : "Data Structure And Algorithm",
"price" : 666.6
}
],
"name" : "Jack",
"car" : {
"price" : 106.666,
"name" : "Bently"
}
}
*/
struct Book: Convertible {
var name: String = ""
var price: Double = 0.0
}
struct Dog: Convertible {
var name: String = ""
var age: Int = 0
}
struct Person: Convertible {
// books can alse be NSArray\NSMutableArray
var books: [Any]? = [
Book(name: "Fast C++", price: 666.6),
Book(name: "Data Structure And Algorithm", price: 666.6),
]
// dogs can alse be NSDictionary\NSMutableDictionary
var dogs: [String: Any]? = [
"dog0": Dog(name: "Wang", age: 5),
"dog1": Dog(name: "ErHa", age: 3),
]
}
let jsonString = Person().kj.JSONString()
/*
{
"dogs" : {
"dog1" : {
"age" : 3,
"name" : "ErHa"
},
"dog0" : {
"age" : 5,
"name" : "Wang"
}
},
"books" : [
{
"name" : "Fast C++",
"price" : 666.6
},
{
"price" : 1666.6,
"name" : "Data Structure And Algorithm"
}
]
}
*/
struct Car: Convertible {
var name: String = ""
var price: Double = 0.0
}
// models can alse be NSArray\NSMutableArray
let models = [
Car(name: "BMW", price: 100.0),
Car(name: "Audi", price: 70.0),
Car(name: "Bently", price: 300.0)
]
let jsonString1 = models.kj.JSONString()
// gloabal function `JSONString(from:)`
let jsonString2 = JSONString(from: models)
/*
[
{
"name" : "BMW",
"price" : 100
},
{
"price" : 70,
"name" : "Audi"
},
{
"price" : 300,
"name" : "Bently"
}
]
*/
struct Car: Convertible, Hashable {
var name: String = ""
var price: Double = 0.0
}
let models: Set<Car> = [
Car(name: "BMW", price: 100.0),
Car(name: "Audi", price: 70.0),
Car(name: "Bently", price: 300.0)
]
let jsonString = models.kj.JSONString()
/*
[
{
"price" : 70,
"name" : "Audi"
},
{
"price" : 300,
"name" : "Bently"
},
{
"name" : "BMW",
"price" : 100
}
]
*/
struct Dog: Convertible {
var nickName: String = "Wang"
var price: Double = 100.6
func kj_JSONKey(from property: Property) -> JSONPropertyKey {
switch property.name {
case "nickName": return "_nick_name_"
default: return property.name
}
}
}
let jsonString = Dog().kj.JSONString()
/* {"price":100.6,"_nick_name_":"Wang"} */
// kj_JSONKey support ConvertibleConfig.
// It is similar to kj_modelKey.
private let dateFmt: DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = "yyyy-MM-dd HH:mm:ss"
return fmt
}()
struct Student: Convertible {
var birthday: Date?
func kj_JSONValue(from modelValue: Any?, _ property: Property) -> Any? {
if property.name != "birthday" { return modelValue }
return birthday.flatMap(dateFmt.string)
}
}
let time = "2019-08-13 12:52:51"
let date = dateFmt.date(from: time)
let student = Student(birthday: date)
let jsonString = student.kj.JSONString()
/* {"birthday":"2019-08-13 12:52:51"} */
// kj_JSONValue support ConvertibleConfig.
// It is similar to kj_modelKey.
struct Car: Convertible {
var name: String = "Bently"
var age: Int = 10
// call when will begin to convert from model to json
func kj_willConvertToJSON() {
print("Car - kj_willConvertToJSON")
}
// call when did finish converting from model to json
func kj_didConvertToJSON(json: [String: Any]) {
print("Car - kj_didConvertToJSON", json)
}
}
kakajson's People
Forkers
rmkitty zhangtao159 fwmev mohsinalimat majorshen z624821876 jtyxcode gkwenbo hpdx songhongkang tgy100 andrewheart loverofcode iceysdeng aiyoubug jansenguan ashinerong kerwincheung swyhei8080 luoxiu hu5980 lxf0800 kukumalucn kk-laoguo wangjianqi kira2015 kinarobin fengchenn dmyi buliceli fpjack leiyuncun snaillovesmile youngshingjun ruanjunhao klfljames wangteng6680 lizhi2416 doukingstudy huhuge famile yzc-jason licy9527 douxindong weizhangcoder mitchell-dream hkshensmart ovixxivo 15041397127 xuzhenguo delonchen2011 yyyear wgfcode lijianios ghliangxd 150vb heishzc czycavan zhishouxun mrqinshou fengdeng hubin97 zhuangxq shenglinfl skateliu dqb101140127 inascf silencelove fcf5646448 fuzhiqiang1989 rq0588 slience2015 ovveii zhmios toj-coder aganjiuswo dormitory219 xiaobailong940 lccdl jiang6777 chuan315 dogs1024 wonwinlee asciima snoux fisher158163 roller-coaster bagyaru ilife-x cocodinglee yiwow aidybao poetances helloliyong rbqren000 lastshrek zymxun scyano azu2025 bobwongskakajson's Issues
关于JSONObject
我可以用 这个方法 把服务端的json 中id 转成struct 中的 userID
func kj_modelKey(from property: Property) -> ModelPropertyKey {
switch property.name {
case "id": return "userID"
default:
return property.name
}
}
我怎么样在 转成字典时候 把 “userID” 转成 “ id” 时呢?
真机运行报错
A shell task (/usr/bin/xcrun codesign --force --sign XXX --preserve-metadata=identifier,entitlements /Users/baicai/Library/Developer/Xcode/DerivedData/NXY-gctyqidlfcosnxdvubeulhljuelz/Build/Products/Debug-iphoneos/JKYZF.app/Frameworks/KakaJSON.framework) failed with exit code 1:
/Users/baicai/Library/Developer/Xcode/DerivedData/NXY-gctyqidlfcosnxdvubeulhljuelz/Build/Products/Debug-iphoneos/JKYZF.app/Frameworks/KakaJSON.framework: resource fork, Finder information, or similar detritus not allowed
Command /bin/sh failed with exit code 1
MJ没有想到留一手
swift视频没有讲KakaJSON原理
NSNumber mapping error
let json: Array<Dictionary<String, Any>> = [ [
"name": "KakaJSON",
"id" : NSNumber(6664714503134970889),
"url": "https://github.com/kakaopensource/KakaJSON"
] ,
[
"name": "KakaJSON",
"id" : 6664714503134970881,
"url": "https://github.com/kakaopensource/KakaJSON"
]]
let repo: [Repo] = json.kj.modelArray(type: Repo.self) as! [Repo]
for item in repo {
print(item.id)
}
after mapping, first item is 6664714503134970880, second item is right
Swift Package Manager 依赖出错
初学 iOS,在使用该库时,使用 SPM 添加依赖出错,看提示貌似是包含混合语言,日志如下,请问有人知道如何解吗,还望不吝赐教
Showing All Messages
/Users/mac/Library/Developer/Xcode/DerivedData/QSBoxIOS-gfcoshocdpymxrakohrtjsypvzrm/SourcePackages/checkouts/KakaJSON/Package.swift: target at '/Users/mac/Library/Developer/Xcode/DerivedData/QSBoxIOS-gfcoshocdpymxrakohrtjsypvzrm/SourcePackages/checkouts/KakaJSON/Tests/KakaJSONTests' contains mixed language source files; feature not supported
如果某一属性为空,强制让model转换失败的功能
类似于,如果某个对象有个id属性。需求是某一json数据中,如果该属性对应的字段没有值或者没有该属性对应的字段,则直接忽略其他属性的解析,直接强制让该model解析失败,抛出nil。
Error verifying ipa package
This bundle Payload/XXX.app/Frameworks/KakaJSON.framework is invalid. The Info.plist file is missing the required key: CFBundleVersion. Please find more information about CFBundleVersion at https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion\
无法更新到1.1.2
RT
嵌套 struct 数组 不能解析吗?还是我的用法问题?
struct YFTestUserModel: Convertible {
var headUrl = ""
var userId = ""
var isAdmin = ""
var name = ""
}
struct YFVVVModel: Convertible {
var userId = ""
var name = ""
var members: [YFTestUserModel] = []
}
let json = """
{"userId":"7f6a74a0-309f-4b62-abd3-431ca4a3b933","name":"可口可乐了","members":[{"headUrl":"https://xxx.xx.com/a92cafd5-d2e6-4265-b24c-9c35dd0e7217.jpeg","userId":"abd3-431ca4a3b933","isAdmin":"1","name":"可口可乐了"}]}
"""
let a = json.kj.model(YFVVVModel.self)
//a.members = nil
关于NSNull
let json: [String: Any ] = [
"name": NSNull(),
"weight": 6.66,
]
如果接口返回 为null
struct Cat: Convertible {
var name: String? = ""
var weight: Double?
mutating func kj_didConvertToModel(from json: [String : Any]) {
if name == nil || name == "<null>" {
name = ""
}
}
}
就需要这样处理了,有没有规避null 的处理呢?不想每个属性都加个判断,这样很麻烦呀。
使用了KaKaJSON还有必要使用swiftjson吗
没有出KaKaJSON之前项目中使用了swiftjson,现在使用了KaKaJSON 和之前引入的swiftjson有冲突.请问我可以去掉swiftjson吗还是怎么处理,谢谢
不会触发didSet方法
老师 我最近用你的kakaJSON发现这样一个问题,就是不会触发didSet方法。我一个模型类是这样的
class UserAccount :NSObject, Convertible, NSCoding {
var access_token : String?
/// 过期时间-->秒
var expires_in : TimeInterval = 0.0{
didSet{
expires_date = NSDate(timeIntervalSinceNow: expires_in)
}
}
required override init(){ }
// MARK:- 重写description属性
override var description : String {
return dictionaryWithValues(forKeys: ["access_token", "expires_date", "uid", "screen_name", "avatar_large"]).description
}
}
他不会触发 didSet{ expires_date = NSDate(timeIntervalSinceNow: expires_in) } 导致我的expires_date 没有值,但是我如果用字典转模型那样就是会触发didSet 这个方法 ,我知道原因是 字典转模型的时候 我先创建了这个模型然后在对他赋值的,所以才会触发。但是我想kakaJSON应该也会触发阿 ,拿到他在底层是不创建模型?
这是我调用kakaJSON 的地方
switch (response.result){
case.success(let json):
let jsonObj = JSON.init(json).dictionaryValue
let accoutModel = jsonObj.kj.model(UserAccount.self)
finish(accoutModel)
case .failure(let error):
DGLog(error)
finish(nil)
}
我觉得我 应该是没用错呢 老师!望老师回答!
嵌套解析出错
模型
struct ChatRoomModel: Convertible {
var lastMessage: String = ""
var lastMessageTime: NSNumber = 0
var pkid: NSNumber = 0
var unreadNoticeCount: NSNumber = 0
}
struct WorkShopsModel: Convertible {
var chatRoom: ChatRoomModel?
var imgUrl: String = ""
var isMine: NSNumber = false
var pkid: NSNumber = 0
var unsignined: NSNumber?
var status: NSNumber = 0
var title: String = ""
var regCount: Int?
var tbString: String?
var teString: String?
}
数据
let json =
"""
{
"chatRoom": {
"dataSourceName": "x",
"last_message": "",
"last_message_time": 1567578912000,
"pkid": 2,
"unread_notice_count": 0
},
"dataSourceName": "x",
"img_url": "",
"is_mine": true,
"pk_chatroom": 2,
"pkid": 3,
"reg_count": 1,
"status": 1,
"tbString": "2019-01-30",
"teString": "2019-09-28",
"title": "",
"unsignined": true
}
"""
chatRoom 字段解析出来是 nil
能不能像OC那样无侵入
OC版本的model,可以无侵入的实现数据模型。
请问swift版本有没有这样的能力?是不是swift内部什么机制决定无法实现
write_to,会覆盖原来的对象
write_to,会覆盖原来的对象
iOS 9 Crash
crash at
Thread 1: EXC_BAD_ACCESS (code=1, address=0x100000003) (Type.swift line 47)
use description.pointee on iOS 9
关于 struct 的使用
struct Cat: Convertible {
var name: String?
var weight: Double?
}
这样是可行的
struct Cat: Convertible {
init() {
name = "cyan"
}
let name: String?
var weight: Double?
}
属性 有let的情况 为什么要加个 init()?
Model转json有问题
混编项目闪退
继承RealmSwift,Object 类转模型时崩溃;
崩溃点:KaKaJSON/Type.swift: 47行
47:if !description.pointee.isGeneric { return nil }
Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
归档太耗性能
有的时候,归档处理不好,,非常影响性能,什么时候能上数据库,谢谢
This bundle Payload/JKYZF.app/Frameworks/KakaJSON.framework is invalid.
App Store Connect Operation Error:This bundle Payload/JKYZF.app/Frameworks/KakaJSON.framework is invalid. The Info.plist file is missing the required key: CFBundleVersion
重构项目结构
现在的 KakaJSON 只有 cocoa touch framework 的 scheme,这会让在 macOS app 里使用 Carthage 添加依赖时会找不到对应 scheme 编译。(在 CocoaPods 下没有问题)
需要组织下项目结构:
——可以直接用 spm 重新生成支持多平台的 xcodeproj(建议)。
——也可以手动添加新的 macOS&tvOS schemes。
如果愿意的话我可以提交一个 pr~ 🍻
明杰老师还在继续维护这个库吗
HnadyJson太难用了,升级系统就崩溃。Codeable也不好用
问下有字段映射功能吗?后台返回字段全大写的字段,想修改一下
手动导入KaKaJSON库提示修改
示例中写法解析失败,不知是我写法错误,还是这种写法暂不支持解析
struct HttpResposeData<T: Convertible>: Convertible {
/// 服务器状态码
var code: Int?
/// 服务器消息
var message: String?
/// 数据
var data: T?
init() {
}
}
class KJTestMode: Convertible {
var name: String?
var age: Int = 18
required init() {}
class func testSampleData() {
let jsonString = """
{
"code":1000,
"message":"测试数据",
"data":[
{
"name":"a",
"age":18
},
{
"name":"b",
"age":20
},
{
"name":"c",
"age":"24"
}
]
}
"""
let model = jsonString.kj.model(HttpResposeData<[KJTestMode]>.self)
let model1 = jsonString.kj.model(type: HttpResposeData<[KJTestMode]>.self)
print("testSampleData解析结果\(model),,,,\(model1)")
//testSampleData解析结果Optional(LQTool.HttpResposeData<Swift.Array<LQTool.KJTestMode>>(code: Optional(1000), message: Optional("测试数据"), data: nil)),,,,Optional(LQTool.HttpResposeData<Swift.Array<LQTool.KJTestMode>>(code: Optional(1000), message: Optional("测试数据"), data: nil))
}
class func testSampleData1() {
let jsonString = """
{
"code":0,
"message":"",
"data":{
"key1":{
"name":"a",
"age":18
},
"key2":{
"name":"b",
"age":20
},
"key3":{
"name":"c",
"age":"24"
}
}
}
"""
let model = jsonString.kj.model(HttpResposeData<[String: KJTestMode]>.self)
let model1 = jsonString.kj.model(type: HttpResposeData<[String: KJTestMode]>.self)
print("testSampleData1解析结果\(model),,,,\(model1)")
//testSampleData1解析结果Optional(LQTool.HttpResposeData<Swift.Dictionary<Swift.String, LQTool.KJTestMode>>(code: Optional(0), message: Optional(""), data: Optional([:]))),,,,Optional(LQTool.HttpResposeData<Swift.Dictionary<Swift.String, LQTool.KJTestMode>>(code: Optional(0), message: Optional(""), data: Optional([:])))
}
}
extension Array: Convertible where Element: Convertible {
// 添加支持
}
extension Dictionary: Convertible where Value: Convertible {
// 添加支持
}pod error
项目在 Testflight 上会闪退
遇见一个很奇怪的 BUG, 项目在模拟器上运行没有问题, 真机测试也没有问题, Debug 和 Release 都没问题, 上传蒲公英也没有问题, 但上传到 TestFlight 后就会打开就闪退.
崩溃时的环境:
系统: 10.15.1
Xcode: 11.2
使用 Swift 5
包管理: Xcode 自带 SPM
最后一次正常的环境:
系统: 10.15
Xcode: 11.1
使用 Swift 5
包管理: Xcode 自带 SPM
Xcode 版本 11.0 ~ 11.2 都试过, 都是同样的问题.
在前几天的一个打包版本之前还是好的, 但之后的打包版本都不行, 即使 git 退回到那个正常的分支再打包也不行, 最后在 Xcode 11.0 上尝试关闭 bitcode 和 strip swift symbols 后打包可以正常运行, 但在 Xcode 11.2 上打包依然闪退.
在 stackover flow 上有人提示 Xcode 11.2 已在 2019.11.5 被官方弃用, 就把 Xcode 更新到了 11.2.1, bitcode 和 strip swift symbols 均开启, 然后在 scheme 改为 release 后模拟器运行终于出现闪退.
之后在 Xcode 11.2.1 上测试 , bitcode 和 strip swift symbols 选项和这个崩溃无关, 不管开启关闭, 崩溃依然.
json 文件已通过格式化工具检验通过, 可以正常读取与解析, 控制台打印数据是正确的.
目前已改为 ObjectMapper 解析 json, 一切正常.
建议引入头文件,方便工程引用
由于没有头文件,在用到KakaJSON的文件中都需要import一次
Suggested support for Carthage
release 模式下取不出模型里的 Int类型的值
模型
struct BookResource: Convertible {
enum ResourceType {
case picture
case pictureFllowRead
case video
case audio
case demo
case test
case weike
case unkown
}
let rID: Int = 0
let rName: String = ""
let ext: String = ""
let showNum: Int = 0
let fileType: Int = 0
let chapterID: Int = 9991
let sectionID: Int = 0
let downloadPath: String = ""
let ossName: String = ""
let picOption: Int = 0
let imgType: Int = 0
let fundamentalTone: String = ""
var type: ResourceType {
switch picOption {
case 1:
if imgType == 1 {
return .pictureFllowRead
}
else {
return .picture
}
case 2:
return .demo
case 3:
return .test
case 4:
return .video
case 5:
return .audio
case 6:
return .weike
default:
return .unkown
}
}
func kj_modelKey(from property: Property) -> ModelPropertyKey {
switch property.name {
case "rID": return "r_id"
case "rName": return "r_name"
case "showNum": return "show_num"
case "chapterID": return "chapter_id"
case "sectionID": return "section_id"
case "imgType": return "img_type"
case "fundamentalTone": return "fundamental_tone"
default:
return property.name
}
}
}
在这里用的, 我把打印复制到里边了
static func save(bookID: Int, resource: BookResource) {
dbQueue.inDatabase { db in
let sql: String = """
INSERT OR REPLACE INTO t_resource (user_id, book_id, chapter_id, section_id, r_id, r_name, ext, show_num, fileType, downloadPath, ossName, picOption, img_type, fundamental_tone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"""
let resource = resource
print("resource: \(resource)")
/*
resource: BookResource(rID: 984, rName: "situational prompts", ext: "html", showNum: 1, fileType: 2, chapterID: 58, sectionID: 212, downloadPath: "http://114.116.28.196:9003/wap/getSectionContent_984.html", ossName: "getSectionContent_984", picOption: 2, imgType: 0, fundamentalTone: "")
*/
let resourceID: Int = resource.rID
print("resource.rID: \(resource.rID)")
print("resourceID: \(resourceID)")
/*
resource.rID: 0
resourceID: 0
*/
let arguments: StatementArguments = [userID, bookID, resource.chapterID, resource.sectionID, resourceID, resource.rName, resource.ext, resource.showNum, resource.fileType, resource.downloadPath, resource.ossName, resource.picOption, resource.imgType, resource.fundamentalTone]
print("arguments: \(arguments)")
/*
arguments: [100764, 200121, 9991, 0, 0, "situational prompts", "html", 0, 0, "http://114.116.28.196:9003/wap/getSectionContent_984.html", "getSectionContent_984", 0, 0, ""]
*/
do {
try db.execute(sql: sql, arguments: arguments)
} catch {
debugLog("save a book resource, 操作异常, error: \(error)")
}
}
}
控制台, 可以把值 po 出来
(lldb) po resource.rID
984
(lldb) po resourceID
0
chapterID, 在使用的时候就是默认值 9991
let chapterID: Int = 9991
AddressSanitizer 报错
thread info -s
thread #1: tid = 0x56556c, 0x00000001067bd74c libclang_rt.asan_ios_dynamic.dylib`__asan::AsanDie(), queue = 'com.apple.main-thread', stop reason = Global buffer overflow
{
"access_size": 44,
"access_type": 0,
"address": 4460594657,
"description": "global-buffer-overflow",
"instrumentation_class": "AddressSanitizer",
"pc": 4403555236,
"stop_type": "fatal_error"
}
var practiceCountDatas: [[String: Any]] = [["count": 3, "countText": "3题", "isSelected": false],
["count": 5, "countText": "5题", "isSelected": false],
["count": 10, "countText": "10题", "isSelected": false]]
var models = modelArray(from: practiceCountDatas, XZPracticeCountModel.self)
private struct XZPracticeCountModel: Convertible {
var count: Int = 0
var countText: String?
var isSelected: Bool = false
}
数组解析nil, 麻烦看一下
git 上面的例子运行也是nil
在Generic
let response2 = json2.kj.model(NetResponse<[Goods]>.self)
手册
泛型 41行
不维护了吗
正准备用,还维护吗
对象key为类似“ LifeTips”的解析失败,解析为nil
如题,遇到对象是key是类似LifeTips的会解析失败,全部为nil,希望明杰老师指点迷津
和原生的 JSONEncoder 和 JSONDecoder 有啥区别 有性能对比吗?
还会继续维护吗?
MJ大神,这个轮子还会继续维护吗?
Optional<Model>没有JSONString方法
struct Model: Convertible {
var coordinate: [[Double]] = []
}
let json = [
"coordinate": [
[1.0, 2.0],
[3.0, 4.0],
[5.0, 6.0]
]
]
let model = json.kk.model(Model.self) //model 是 Model?类型, Opetional没有JSONString()方法
print(model.kk.JSONString()) //Value of type 'KKGeneric<Model?, Model>' has no member 'JSONString'
if let model = json.kk.model(Model.self) {
print(model.kk.JSONString()) //这个正常
}
启用 BUILD_LIBRARY_FOR_DISTRIBUTION 后 class 序列化造成奔溃
@CoderMJLee 在项目二进制化的过程中,发现如果启用 BUILD_LIBRARY_FOR_DISTRIBUTION 后,在跨模块使用类继承的模式下,会造成奔溃。希望能帮助解决一下。
Example
// Module A
open class BaseModel: Convertible {
public var baseVarInt: Int?
public var baseVarString: String?
required public init() {}
}
// Module B
import MoudleA
public class ChildModel: BaseModel {
public var childVarInt: Int?
public var childVarString: String?
}
let model = jsonString.kj.model(ChildModel.self)最小可复现项目可查看该 链接
是不是不维护了???
Invalid redeclaration of 'modelArray(from:anyType:)'
pod引入的 报这个错。。 求大神说下怎么调
模型中的属性名与json中的key不一样,怎么替换
Hi,使用的时候发现:解析大的 Int 数据会失败
` static func number( value: Any, _ type: Any.Type) -> NumberValue? {
guard let str = _numberString(value) else { return nil }
guard let decimal = Decimal(string: str) else { return nil }
// digit
if let digitType = type as? DigitValue.Type {
// 大 Int 数据解析永远是 18035768958676992
// let x = 18035768958676993, // 解析失败, 解析结果成 18035768958676992
// let y = 18035768958676992 // 解析成功
return Double("\(decimal)")
.flatMap { NSNumber(value: $0) }
.flatMap { digitType.init(truncating: $0) }
}
// decimal number
if type is NSDecimalNumber.Type {
return NSDecimalNumber(decimal: decimal)
}
// decimal
if type is Decimal.Type { return decimal }
// other
return Double("\(decimal)").flatMap { NSNumber(value: $0) }
}
`
数组嵌套数组的模型好像解析不了
比如这样的: [[SomeModel]] 就无法解析成功
他来了他来了,他带着JSON走来了~
赶紧弃坑HandyJSON吧~
Towards the Peak of Life follow the Kaka Roter~
看了下手册,没有看见关于泛型的,不知道是否支持泛型
比如后台返回的所有的数据都是 [data: [String: Any], msg: String, code: Int]
struct User {
let id: String
let nickName: String
}
struct Goods {
let price: CGFloat
let name: String
}
struct NetResponse<Element> {
let data: Element
let msg: String
let code: Int
}
不知道是否支持以下这种解析
let json1 = """
{
"data": {"nickName": "KaKa","id": 213234234},
"msg": "请求成功",
"code" : 200
}
"""
let response1 = josn1.kj.model(NetResponse<User>.self)
let user: User = response1.data
let json2 = """
{
"data": [
{"price": "6199", "name": "iPhone XR"},
{"price": "8199", "name": "iPhone XS"},
{"price": "9099", "name": "iPhone Max"}
],
"msg": "请求成功",
"code" : 200
}
"""
let response2 = json2.kj.model(NetResponse<[Goods]>.self)
let items: [Goods] = response2..dataenum 加@objc标签解析时会崩溃
转换代码如下:
@objcMembers class CustomerQuestionTypeResp: NSObject, Convertible {
@objc enum QuestionType: Int, ConvertibleEnum {
case singleSelect = 0
case multiSelect = 1
case unsureSelect = 2
case judge = 3
case fillBlank = 4
case input = 5
case material = 6
}
var type: QuestionType = .singleSelect
required override init() {
super.init()
}
}
QuestionType在不标记@objc 的情况下解析正常,加了@objc标签后估计是偏移量有变化导致解析崩溃,崩溃位置如下:

Key path matched wrong value
In some cases, kj_value(for modelPropertyKey: ModelPropertyKey) will return a wrong value if the key is an array. For example:
struct Battle: Convertible {
var winner: String?
func kj_modelKey(from property: Property) -> ModelPropertyKey {
switch property.name {
case "winner": return ["teams", "0", "name"]
default: return property.name
}
}
}
let json: [String: Any] = [
"teams": [
["name": "luoxiu"]
]
]
let battle = json.kj.model(Battle.self)
print(battle.winner) // expect "luoxiu", got "[[\"name\": \"luoxiu\"]]"
This is because of these few lines of code:
// in `kj_value(for modelPropertyKey: ModelPropertyKey)`
let keyArray = modelPropertyKey as! [String]
for key in keyArray {
if let value = _value(stringKey: key) {
// shoud not return if the value is a dict/array and the key path is not empty I think?
return value
}
}
Will create a pr with fixing later.
description.pointee.isGeneric代码崩溃stop reason = EXC_BAD_ACCESS
杰哥,你好,想使用KakaJSON获取类的metadata数据,遇到一个崩溃
- 1、有一个OC的类
WTStudent
@interface WTStudent : NSObject
@end
@interface WTPerson : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSUInteger age;
@property (nonatomic, strong) WTStudent *stu;
@end
- 2、Swift中的
Student继承WTPerson
class Student: WTPerson {
}
- 3、获取
Student的MetaData数据
let mt = Metadata.type(Student.self) as? ModelType
- 4、崩溃点
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x2c)
frame #0: 0x00007fff51b2c94d libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 77
frame #1: 0x0000000100b7398b Metadata扫描`__swift_memcpy60_4 at <compiler-generated>:0
* frame #2: 0x0000000100b5276d Metadata扫描`NominalType<>.builtGenericTypes(self=0x00006000022f4630) at Type.swift:47:25
frame #3: 0x0000000100b437c0 Metadata扫描`ClassType.build(self=0x00006000022f4630) at ClassType.swift:18:24
frame #4: 0x0000000100b561a2 Metadata扫描`BaseType.init(name="WTPerson", type=WTPerson, kind=class, self=0x00006000022f4630) at BaseType.swift:22:9
frame #5: 0x0000000100b6282e Metadata扫描`ModelType.init(name="WTPerson", type=WTPerson, kind=class) at <compiler-generated>:0
frame #6: 0x0000000100b44b3b Metadata扫描`ClassType.init(name="WTPerson", type=WTPerson, kind=class) at <compiler-generated>:0
frame #7: 0x0000000100b449bc Metadata扫描`ClassType.__allocating_init(name:type:kind:) at ClassType.swift:0
frame #8: 0x0000000100b72c9d Metadata扫描`static Metadata.type(type=WTPerson, self=Metadata扫描.Metadata) at Metadata.swift:49:22
frame #9: 0x0000000100b4390c Metadata扫描`ClassType.build(self=0x00006000022f45a0) at ClassType.swift:21:28
frame #10: 0x0000000100b561a2 Metadata扫描`BaseType.init(name="Student", type=Metadata扫描.Student, kind=class, self=0x00006000022f45a0) at BaseType.swift:22:9
frame #11: 0x0000000100b6282e Metadata扫描`ModelType.init(name="Student", type=Metadata扫描.Student, kind=class) at <compiler-generated>:0
frame #12: 0x0000000100b44b3b Metadata扫描`ClassType.init(name="Student", type=Metadata扫描.Student, kind=class) at <compiler-generated>:0
frame #13: 0x0000000100b449bc Metadata扫描`ClassType.__allocating_init(name:type:kind:) at ClassType.swift:0
frame #14: 0x0000000100b72c9d Metadata扫描`static Metadata.type(type=Metadata扫描.Student, self=Metadata扫描.Metadata) at Metadata.swift:49:22
frame #15: 0x0000000100b57001 Metadata扫描`AppDelegate.application(application=0x00007f8ffdf04e80, launchOptions=nil, self=0x00006000010f37c0) at AppDelegate.swift:20:27
frame #16: 0x0000000100b57183 Metadata扫描`@objc AppDelegate.application(_:didFinishLaunchingWithOptions:) at <compiler-generated>:0
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
OpenClaw
Personal AI Assistant
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.










