kakaopensource / kakajson Goto Github PK
View Code? Open in Web Editor NEWFast conversion between JSON and model in Swift.
License: MIT License
Fast conversion between JSON and model in Swift.
License: MIT License
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()) //这个正常
}
杰哥,你好,想使用KakaJSON获取类的metadata数据,遇到一个崩溃
WTStudent
@interface WTStudent : NSObject
@end
@interface WTPerson : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSUInteger age;
@property (nonatomic, strong) WTStudent *stu;
@end
Student
继承WTPerson
class Student: WTPerson {
}
Student
的MetaData数据let mt = Metadata.type(Student.self) as? ModelType
* 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
由于没有头文件,在用到KakaJSON的文件中都需要import一次
比如这样的: [[SomeModel]] 就无法解析成功
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\
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
初学 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
如题,遇到对象是key是类似LifeTips的会解析失败,全部为nil,希望明杰老师指点迷津
遇见一个很奇怪的 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, 一切正常.
@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)
最小可复现项目可查看该 链接
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.
write_to,会覆盖原来的对象
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 {
// 添加支持
}
正准备用,还维护吗
模型
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
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
` 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) }
}
`
模型
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
swift视频没有讲KakaJSON原理
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 的处理呢?不想每个属性都加个判断,这样很麻烦呀。
HnadyJson太难用了,升级系统就崩溃。Codeable也不好用
pod引入的 报这个错。。 求大神说下怎么调
有的时候,归档处理不好,,非常影响性能,什么时候能上数据库,谢谢
[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..data
OC版本的model,可以无侵入的实现数据模型。
请问swift版本有没有这样的能力?是不是swift内部什么机制决定无法实现
现在的 KakaJSON 只有 cocoa touch framework 的 scheme,这会让在 macOS app 里使用 Carthage 添加依赖时会找不到对应 scheme 编译。(在 CocoaPods 下没有问题)
需要组织下项目结构:
——可以直接用 spm 重新生成支持多平台的 xcodeproj(建议)。
——也可以手动添加新的 macOS&tvOS schemes。
如果愿意的话我可以提交一个 pr~ 🍻
struct Cat: Convertible {
var name: String?
var weight: Double?
}
这样是可行的
struct Cat: Convertible {
init() {
name = "cyan"
}
let name: String?
var weight: Double?
}
属性 有let的情况 为什么要加个 init()?
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
crash at
Thread 1: EXC_BAD_ACCESS (code=1, address=0x100000003) (Type.swift line 47)
use description.pointee
on iOS 9
赶紧弃坑HandyJSON吧~
Towards the Peak of Life follow the Kaka Roter~
老师 我最近用你的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)
}
我觉得我 应该是没用错呢 老师!望老师回答!
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
MJ大神,这个轮子还会继续维护吗?
没有出KaKaJSON之前项目中使用了swiftjson,现在使用了KaKaJSON 和之前引入的swiftjson有冲突.请问我可以去掉swiftjson吗还是怎么处理,谢谢
git 上面的例子运行也是nil
在Generic
let response2 = json2.kj.model(NetResponse<[Goods]>.self)
手册
泛型 41行
我可以用 这个方法 把服务端的json 中id 转成struct 中的 userID
func kj_modelKey(from property: Property) -> ModelPropertyKey {
switch property.name {
case "id": return "userID"
default:
return property.name
}
}
我怎么样在 转成字典时候 把 “userID” 转成 “ id” 时呢?
类似于,如果某个对象有个id属性。需求是某一json数据中,如果该属性对应的字段没有值或者没有该属性对应的字段,则直接忽略其他属性的解析,直接强制让该model解析失败,抛出nil。
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
}
转换代码如下:
@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标签后估计是偏移量有变化导致解析崩溃,崩溃位置如下:
RT
崩溃点:KaKaJSON/Type.swift: 47行
47:if !description.pointee.isGeneric { return nil }
Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.