QwikJson
[](https://travis-ci.org/Logan Sease/QwikJson)
摘要
在我们 ReSTful API 世界中,我们始终向我们的 api 传递 JSON 对象并从中接收它们。不断将这些对象序列化为 JSON 字符串和字典,再从字典序列化到对象,可能会非常麻烦,并且可能导致您的模型类和数据处理服务开始填充样板代码解析。
为了解决这个问题,我引入了 QwikJson。这是一个强大而简单的库,用于序列化和反序列化 JSON 对象。
只需让您的模型类继承自 QwikJson,这个世界将向您敞开。
QwikJson 使对象转换为字典和字典数组(反之亦然)变得非常简单。它支持嵌套模型对象、嵌套数组模型对象、多种日期和时间格式,以及将数据和从 JSON 字符串转换的功能。
安装
QwikJson可以通过CocoaPods获取。要安装它,只需将以下行添加到您的Podfile中
pod "QwikJson"
并导入以下头文件
#import "QwikJson.h"
此pod用Objective-C编写,但与Swift项目也运作良好。
用法
As of Swift 3, all swift properties must contain the @objc tag to be visible to swift
创建一个模型类并扩展QwikJson,并添加您的字段
//menu.h
@interface Menu : QwikJson
@property(nonatomic,strong)NSString * name;
@property(nonatomic,strong)NSArray * menuItems;
@end
class Menu : QwikJson
{
@objc var name : String?
}
现在您可以从字典和相反方向转换,更轻松了
//deserialize
menu = [Menu objectFromDictionary:dictionary];
//serialize again
dictionary = [menu toDictionary];
使用嵌套对象(即使是嵌套数组)和自定义日期序列化器
//restaurant.h
@interface Restaurant : QwikJson
@property(nonatomic,strong)NSString * image_url;
@property(nonatomic,strong)NSString * name;
@property(nonatomic,strong)NSArray * menus;
@property(nonatomic,strong)DBTimeStamp * createdAt;
@end
+(Class)classForKey:(NSString*)key
{
if([key isEqualToString:@"menus"])
{
return [Menu class];
}
if([key isEqualToString:@"createdAt"])
{
return [DBTimeStamp class];
}
return [super classForKey:key];
}
或者用Swift
class Restaurant: QwikJson {
@objc var imageUrl: String?
@objc var name: String?
@objc var menus: [Menu] = []
@objc var createdAt: DBTimeStamp?
override public class func type(forKey: String!) -> AnyClass!
{
if forKey == "createdAt"
{
return DBTimeStamp
}
if forKey == "menu"
{
return Menu.self
}
return super.type(forKey: forKey)
}
}
在序列化或反序列化时执行特定逻辑。
//override in subclass to perform some custom deserizliation or change property keys
-(void)writeObjectFrom:(NSDictionary*)inputDictionary forKey:(NSString*)key toProperty:(NSString*)property
{
//adjust the property name since the database is formatted with _'s instead of camel case
if([property isEqualToString:@"menu_items"])
{
property = @"menuItems";
}
[super writeObjectFrom:inputDictionary forKey:key toProperty:property];
}
//override in subclass to specify a new key or perform some custom action on serialize
-(void)serializeObject:(NSObject*)object withApiKey:(NSString*)apiKey fromKey:(NSString*)objectKey toDictionary:(NSMutableDictionary*)dictionary
{
//adjust the property name since the database is formatted with _'s instead of camel case
if([objectKey isEqualToString:@"menuItems"])
{
apiKey = @"menu_items";
}
[super serializeObject:object withApiKey:apiKey fromKey:objectKey toDictionary:dictionary];
}
定义一个属性映射来指定模型对象和API中对象字段的名称不同。这在您使用保留关键字如“description”或API返回下划线名称字段时可能是必要的。
+(NSDictionary<NSString*,NSString*>*)apiToObjectMapping
{
//specify custom field mappings for qwikJsonObjects
return @{@"description": @"descriptionText"};
}
定义一个临时属性数组来指定在序列化时不应写入的属性。请注意,某些字段默认标记为临时。这些如下:#define kDefaultTransientProperties @[@"superclass", @"hash", @"debugDescription", @"description"] 如果您想传递这些变量中的任何一个,只需使用apiToObjectMapping方法重命名字段即可。
+(NSArray<NSString*>*)transientProperties
{
return @{@"someCalculatedFieldName"};
}
直接写入首选项设置
[self.restaurant writeToPreferencesWithKey:@"data"];
self.restaurant = [Restaurant readFromPrefencesWithKey:@"data"];
转换成字符串和相反操作
@interface NSDictionary (QwikJson)
-(NSString*)toJsonString;
+(NSDictionary*)fromJsonString:(NSString*)json;
@end
@interface NSArray (QwikJson)
-(NSString*)toJsonString;
+(NSArray*)fromJsonString:(NSString*)json;
@end
支持的字段类型
- 布尔值 / Bool
- NSString / String
- NSArray / []
- NSNumber
- NSDecimalNumber(但您必须在classForKey:中指定类型)
-
注意,如果您在使用Swift并且正在使用布尔值,请使用Bool。不要使用Bool?,因为在Objective-C中不能表达可选布尔值。
-
另一个注意:当使用Swift 4时,所有Swift属性都必须以前缀@objc开头,以便它们可读。
自定义日期序列化器,处理解析 Various 日期/时间格式
DBDate
2015-12-30
DBDateTime
2015-01-01T10:15:30
DBTimeStamp
0312345512
DBTime
12:00:00
请注意,您可以通过在日期类上调用 setDateFormat 来自定义日期格式。或者,如果主要格式解析失败,可以调用 setAlternateDateFormats 提供一个交替格式的数组
[DBDate setDateFormat:@"MM/DD/YYYY"];
对于 DBTimeStamp,如果您 API 返回的是毫秒而不是秒,可以设置一个乘数以支持毫秒格式
[DBTimeStamp setTimeStampMultiplier: 1000.0f];
数字/字符串兼容性
如果您的 API 有时在数字字段中返回字符串,或者您正在支持 NSDecimalNumber 以支持高精度数字(在这种情况下,您的 API 可能将它们序列化为字符串),则可以使用 classForKey 方法指定类型,解析器将检查以确保正确反序列化
@property NSNumber* amount;
@property NSDecimalNumber* cost;
//restaurant.m
+(Class)classForKey:(NSString*)key
{
if([key isEqualToString:@"amount"])
{
return [NSNumber class];
}
if([key isEqualToString:@"cost"])
{
return [NSDecimalNumber class];
}
return [super classForKey:key];
}
序列化Null
默认情况下不会序列化Null,但存在全局设置以及每个对象的设置来决定是否应该序列化 Null。
[QwikJson setSerializeNullsByDefault:YES];
object.serializeNulls = kNullSerializationSettingDoNotSerialize;
支持NSManagedObject
如果您正在使用CoreData并希望使用QwikJson,也可以简单地导入并扩展QwikJsonManagedObject而不是直接使用QwikJson。
Android
在这个仓库和android目录中,您还将找到一个非常相似的类,QwikJson.java,它为Android和其他Java平台提供了类似的功能。
更多提示
除了解析和序列化JSON之外,与其他RESTful API通信的另一个关键部分是良好的网络库。请考虑使用QwikHttp与此库结合使用,以完善您的工具集。[A链接](https://github.com/logansease/QwikHttp)
同时,请检查SeaseAssist pod,它提供了一大堆辅助工具来使您的iOS代码编写更加简单
作者
Logan Sease, [B电子邮件](/cdn-cgi/l/email-protection#d8b4abbdb9abbd98bfb5b9b1b4f6bbb7b5)
许可证
QwikJson 在 MIT 许可下可用。有关更多信息,请参阅 LICENSE 文件。