用 KVC 自動把 JSON 轉 Model
來源:程序員人生 發布時間:2015-03-27 08:31:56 閱讀次數:4186次

圖1和圖2是1個接口,code 是在服務器修改或升級等緣由致使的;圖3是在新用戶登錄沒有數據的情況出現的;是1個接口對應的Model類也是1個;Model類代碼以下
@interface SHYProduct : NSObject
@property (nonatomic, assign) int code;
@property (nonatomic, strong) NSString *msg;
@property (nonatomic, strong) NSArray *data;
@end
@interface SHYProductItem : NSObject
@property (nonatomic, strong) NSString *title;
@end
#import "SHYProduct.h"
@implementation SHYProduct
- (void)dealloc
{
_msg = nil;
_data = nil;
}
@end
@implementation SHYProductItem
- (void)dealloc
{
_title = nil;
}
@end
之前我們在轉Model是這樣寫的
NSString *json = @"{"code":"200","msg":"u83b7u53d6u6210u529f","data":[{"title":"title 3"},{"title":"title 4"}]}";
NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *body = kNSDictionary([NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil]);
SHYProduct *product = [[SHYProduct alloc] init];
product.code = [body intForKey:@"code"];
product.msg = [body stringForKey:@"msg"];
NSArray *rows = [body arrayForKey:@"data"];
NSMutableArray *items = [[NSMutableArray alloc] init];
for (id row in rows) {
NSDictionary *dictionary = kNSDictionary(row);
SHYProductItem *item = [[SHYProductItem alloc] init];
item.title = [dictionary stringForKey:@"title"];
[items addObject:item];
}
product.data = items;
這樣寫沒有甚么錯,唯1的是代碼大,體力活;
關于 intForKey 之類的方法請看 網絡接口協議
JSON 解析 Crash 的哪些事
如果我們不想做這個體力活;有無辦法呢;辦法是有1個的,用KVC + Runtime;在用這個之前我們要確認1點用KVC code字段有數字和字符串能不能轉成int類型;是不是可以測試1下就知道;代碼以下:
NSString *json = @"{"code":"200","msg":"u83b7u53d6u6210u529f","data":[{"title":"title 3"},{"title":"title 4"}]}";
NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *body = kNSDictionary([NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil]);
SHYProduct *product = [[SHYProduct alloc] init];
[product setValue:[body valueForKey:@"code"] forKey:@"code"];//這里會轉成數字,KVC自動轉換了
[product setValue:[body valueForKey:@"msg"] forKey:@"msg"];
NSArray *rows = [body arrayForKey:@"data"];
NSMutableArray *items = [[NSMutableArray alloc] init];
for (id row in rows) {
NSDictionary *dictionary = kNSDictionary(row);
SHYProductItem *item = [[SHYProductItem alloc] init];
[item setValue:[dictionary valueForKey:@"title"] forKey:@"title"];
[items addObject:item];
}
product.data = items;
運行1下code值過去了;JSON的code是數字和字符串最后都能變成int類型;這下好辦了寫1個Model基類就能夠替換體力活了;代碼以下:(開源代碼https://github.com/elado/jastor)
#import <Foundation/Foundation.h>
/*!
@class SHYJastor
@abstract 把 NSDictionary 轉成 model 用的
*/
@interface SHYJastor : NSObject<NSCoding>
/*!
@property objectId
@abstract 對象的id
*/
@property (nonatomic, copy) NSString *objectId;
/*!
@method objectWithDictionary:
@abstract 指定 NSDictionary 對象轉成 model 對象
@param dictionary NSDictionary的對象
@result 返回 model 對象
*/
+ (id)objectWithDictionary:(NSDictionary *)dictionary;
/*!
@method initWithDictionary:
@abstract 指定 NSDictionary 對象轉成 model 對象
@param dictionary NSDictionary的對象
@result 返回 model 對象
*/
- (id)initWithDictionary:(NSDictionary *)dictionary;
/*!
@method dictionaryValue
@abstract 把對象轉成 NSDictionary 對象
@result 返回 NSDictionary 對象
*/
- (NSMutableDictionary *)dictionaryValue;
/*!
@method mapping
@abstract model 屬性 與 NSDictionary 不1至時的映照
*/
- (NSDictionary *)mapping;
@end
#import "SHYJastor.h"
#import "SHYJastorRuntimeHelper.h"
#import "NSArray+SHYUtil.h"
#import "NSDictionary+SHYUtil.h"
static NSString *idPropertyName = @"id";
static NSString *idPropertyNameOnObject = @"objectId";
@implementation SHYJastor
Class dictionaryClass;
Class arrayClass;
+ (id)objectWithDictionary:(NSDictionary *)dictionary
{
id item = [[self alloc] initWithDictionary:dictionary];
return item;
}
- (id)initWithDictionary:(NSDictionary *)dictionary
{
if (!dictionaryClass)
dictionaryClass = [NSDictionary class];
if (!arrayClass)
arrayClass = [NSArray class];
self = [super init];
if (self) {
NSDictionary *maps = [self mapping];
NSArray *propertys = [SHYJastorRuntimeHelper propertyNames:[self class]];
for (NSDictionary *property in propertys) {
NSString *propertyName = [property stringForKey:@"name"];
id key = [maps valueForKey:propertyName];
id value = [dictionary valueForKey:key];
if (value == [NSNull null] || value == nil) {
continue;
}
if ([SHYJastorRuntimeHelper isPropertyReadOnly:[property stringForKey:@"attributes"]]) {
continue;
}
if ([value isKindOfClass:dictionaryClass]) {
Class aClass = NSClassFromString([property stringForKey:@"type"]);
if (![aClass isSubclassOfClass:[NSDictionary class]]) {
continue;
}
value = [[aClass alloc] initWithDictionary:value];
}
else if ([value isKindOfClass:arrayClass]) {
NSArray *items = (NSArray *)value;
NSMutableArray *objects = [NSMutableArray arrayWithCapacity:[items count]];
for (id item in items) {
if ([[item class] isSubclassOfClass:dictionaryClass]) {
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@Class", propertyName]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
Class aClass = ([[self class] respondsToSelector:selector]) ? [[self class] performSelector:selector] : nil;
#pragma clang diagnostic pop
if ([aClass isSubclassOfClass:[NSDictionary class]]) {
[objects addObject:item];
}
else if ([aClass isSubclassOfClass:[SHYJastor class]]) {
SHYJastor *childDTO = [[aClass alloc] initWithDictionary:item];
[objects addObject:childDTO];
}
}
else {
[objects addObject:item];
}
}
value = objects;
}
[self setValue:value forKey:propertyName];
}
id objectId;
if ((objectId = [dictionary objectForKey:idPropertyName]) && objectId != [NSNull null]) {
if (![objectId isKindOfClass:[NSString class]]) {
objectId = [NSString stringWithFormat:@"%@", objectId];
}
[self setValue:objectId forKey:idPropertyNameOnObject];
}
}
return self;
}
- (void)dealloc
{
_objectId = nil;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:_objectId forKey:idPropertyNameOnObject];
NSArray *propertys = [SHYJastorRuntimeHelper propertyNames:[self class]];
for (NSDictionary *property in propertys) {
NSString *propertyName = [property stringForKey:@"name"];
[encoder encodeObject:[self valueForKey:propertyName] forKey:propertyName];
}
}
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if (self) {
[self setValue:[decoder decodeObjectForKey:idPropertyNameOnObject] forKey:idPropertyNameOnObject];
NSArray *propertys = [SHYJastorRuntimeHelper propertyNames:[self class]];
for (NSDictionary *property in propertys) {
NSString *propertyName = [property stringForKey:@"name"];
if ([SHYJastorRuntimeHelper isPropertyReadOnly:[property stringForKey:@"attributes"]]) {
continue;
}
id value = [decoder decodeObjectForKey:propertyName];
if (value != [NSNull null] && value != nil) {
[self setValue:value forKey:propertyName];
}
}
}
return self;
}
- (NSMutableDictionary *)dictionaryValue
{
NSMutableDictionary *infos = [NSMutableDictionary dictionary];
if (_objectId) {
[infos setObject:_objectId forKey:idPropertyName];
}
NSDictionary *maps = [self mapping];
NSArray *propertys = [SHYJastorRuntimeHelper propertyNames:[self class]];
for (NSDictionary *property in propertys) {
NSString *propertyName = [property stringForKey:@"name"];
id value = [self valueForKey:propertyName];
if (value && [value isKindOfClass:[SHYJastor class]]) {
[infos setObject:[value dictionary] forKey:[maps valueForKey:propertyName]];
}
else if (value && [value isKindOfClass:[NSArray class]] && ((NSArray *)value).count > 0) {
id internalValue = [value objectForKeyCheck:0];
if (internalValue && [internalValue isKindOfClass:[SHYJastor class]]) {
NSMutableArray *internalItems = [NSMutableArray array];
for (id item in value) {
[internalItems addObject:[item dictionary]];
}
[infos setObject:internalItems forKey:[maps valueForKey:propertyName]];
}
else {
[infos setObject:value forKey:[maps valueForKey:propertyName]];
}
}
else if (value != nil) {
[infos setObject:value forKey:[maps valueForKey:propertyName]];
}
}
return infos;
}
- (NSDictionary *)mapping
{
NSArray *properties = [SHYJastorRuntimeHelper propertyNames:[self class]];
NSMutableDictionary *maps = [[NSMutableDictionary alloc] initWithCapacity:properties.count];
for (NSDictionary *property in properties) {
NSString *propertyName = [property stringForKey:@"name"];
[maps setObject:propertyName forKey:propertyName];
}
return maps;
}
- (NSString *)description
{
NSMutableDictionary *dictionary = [self dictionaryValue];
return [NSString stringWithFormat:@"#<%@: id = %@ %@>", [self class], _objectId, [dictionary description]];
}
- (BOOL)isEqual:(id)object
{
if (object == nil || ![object isKindOfClass:[SHYJastor class]]) {
return NO;
}
SHYJastor *model = (SHYJastor *)object;
return [_objectId isEqualToString:model.objectId];
}
@end
@interface SHYJastorRuntimeHelper : NSObject
+ (BOOL)isPropertyReadOnly:(NSString *)attributes;
+ (NSArray *)propertyNames:(__unsafe_unretained Class)aClass;
@end
#import <objc/runtime.h>
#import "SHYJastor.h"
#import "SHYJastorRuntimeHelper.h"
#import "NSArray+SHYUtil.h"
#import "NSDictionary+SHYUtil.h"
#include <string.h>
static NSMutableDictionary *propertyListByClass;
static const char *property_getTypeName(const char *attributes) {
char buffer[strlen(attributes) + 1];
strncpy(buffer, attributes, sizeof(buffer));
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T') {
size_t len = strlen(attribute);
attribute[len - 1] = '
主站蜘蛛池模板:
欧美一级一毛片
|
欧美a在线
|
视频在线高清完整免费观看
|
欧美一级片免费观看
|
成人亚洲国产精品久久
|
手机看片日韩高清国产欧美
|
亚洲国产人久久久成人精品网站
|
好大好湿好硬顶到了好爽在
|
精品国产一区二区三区久久影院
|
99精品国产美女福到在线不卡
|
日韩欧美一区二区中文字幕
|
国产成人高清精品免费5388密
|
亚洲精品国产77777
|
日本一区二区三
|
久久精品一品道久久精品9
久久精品一区二区
|
男女xx00
|
狠狠躁天天躁夜夜躁夜天战
|
亚洲五月婷婷
|
国产又黄又爽又色的免费
|
国产视频二区在线观看
|
国产一区视频在线播放
|
日韩人成
|
亚洲永久精品一区二区三区
|
亚洲精品人成在线观看
|
99热色|
亚洲精品福利在线观看
|
亚洲国产一区视频
|
一区二区三区网站
|
日本欧美一区二区三区
|
精彩视频一区二区三区
|
国产精品第1页在线播放
|
一区二区三区在线播放
|
日韩在线 | 中文
|
亚洲精品日本
|
国内交换一区二区三区
|
亚洲人成图片欧美人成图片
|
网友自拍区一区二区三区
|
国产一区亚洲欧美成人
|
国产亚洲福利精品一区二区
|
free 英国性xxxxhd
|
性欧美黑人
|