JSONをKVCで自動的にモデルに回します
16541 ワード
【図1】codeがサーバの変更またはアップグレードなどの原因で生じるインタフェースである.【図3】新規ユーザがデータを登録していない場合に現れる.インタフェースに対応するModelクラスでもあります.Modelクラスコードは次のとおりです.
以前モデルを回してこう書いていました
このように書くのは間違いなく、唯一のコードが大きく、体力が働いています.
intForKeyなどの方法については、ネットワークインタフェースプロトコルJSONがCrashを解析する方法を見てください.
もし私たちがこの体力的な仕事をしたくないなら.仕方ないでしょうか.方法は一つあります.KVC+Runtimeを使います.これを使う前に、KVC codeフィールドで数字と文字列がintタイプに変換できるかどうかを確認します.テストしてもいいですか.コードは次のとおりです.
コード値を実行してください.JSONのコードは数字と文字列が最後にintタイプになる.これでモデルベース類を書くと体力の代わりに生きることができます.コードは次のとおりです.(オープンソースコード)https://github.com/elado/jastor)
このベースクラスModelクラスでも修正してください.コードは次のとおりです.
外部用は便利です.コードは次のとおりです.
Modelがもっと上手に書けば、data属性をitemsに変更することができます.コードは以下の通りです.
見たでしょう、便利でしょう、体力の仕事はさようなら
@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
以前モデルを回してこう書いていました
NSString *json = @"{\"code\":\"200\",\"msg\":\"\u83b7\u53d6\u6210\u529f\",\"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;
このように書くのは間違いなく、唯一のコードが大きく、体力が働いています.
intForKeyなどの方法については、ネットワークインタフェースプロトコルJSONがCrashを解析する方法を見てください.
もし私たちがこの体力的な仕事をしたくないなら.仕方ないでしょうか.方法は一つあります.KVC+Runtimeを使います.これを使う前に、KVC codeフィールドで数字と文字列がintタイプに変換できるかどうかを確認します.テストしてもいいですか.コードは次のとおりです.
NSString *json = @"{\"code\":\"200\",\"msg\":\"\u83b7\u53d6\u6210\u529f\",\"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;
コード値を実行してください.JSONのコードは数字と文字列が最後にintタイプになる.これでモデルベース類を書くと体力の代わりに生きることができます.コードは次のとおりです.(オープンソースコード)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
*/
- (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 dictionaryValue] forKey:[maps valueForKey:propertyName]];
}
else if (value && [value isKindOfClass:[NSArray class]] && ((NSArray *)value).count > 0) {
id internalValue = [value objectAtIndexCheck:0];
if (internalValue && [internalValue isKindOfClass:[SHYJastor class]]) {
NSMutableArray *internalItems = [NSMutableArray array];
for (id item in value) {
[internalItems addObject:[item dictionaryValue]];
}
[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] = '\0';
static char result[256];
strncpy(result, attribute + 3, len - 2);
return result;
}
}
return "@";
}
@implementation SHYJastorRuntimeHelper
+ (void)initialize
{
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(didReceiveMemoryWarning)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
}
+ (void)didReceiveMemoryWarning
{
[propertyListByClass removeAllObjects];
}
+ (BOOL)isPropertyReadOnly:(NSString *)attributes
{
NSArray *items = [attributes componentsSeparatedByString:@","];
NSString *attribute = [items stringAtIndex:1];
return [attribute rangeOfString:@"R"].length > 0;
}
+ (NSArray *)propertyNames:(__unsafe_unretained Class)aClass
{
if (aClass == [SHYJastor class]) {
return [NSArray array];
}
if (!propertyListByClass) {
propertyListByClass = [[NSMutableDictionary alloc] init];
}
NSString *className = NSStringFromClass(aClass);
NSArray *names = [propertyListByClass arrayForKey:className];
if (names) {
return names;
}
NSMutableArray *items = [NSMutableArray array];
unsigned int itemCount = 0;
objc_property_t *propertys = class_copyPropertyList(aClass, &itemCount);
for (unsigned int i = 0; i < itemCount; ++i) {
objc_property_t property = propertys[i];
const char *name = property_getName(property);
const char *attributes = property_getAttributes(property);
const char *typeName = property_getTypeName(attributes);
NSMutableDictionary *item = [NSMutableDictionary dictionary];
[item setObject:[NSString stringWithUTF8String:name] forKey:@"name"];
[item setObject:[NSString stringWithUTF8String:attributes] forKey:@"attributes"];
[item setObject:[NSString stringWithUTF8String:typeName] forKey:@"type"];
[items addObject:item];
}
free(propertys);
[propertyListByClass setObject:items forKey:className];
NSArray *array = [SHYJastorRuntimeHelper propertyNames:class_getSuperclass(aClass)];
[items addObjectsFromArray:array];
return items;
}
@end
このベースクラスModelクラスでも修正してください.コードは次のとおりです.
@interface SHYProduct : SHYJastor
@property (nonatomic, assign) int code;
@property (nonatomic, strong) NSString *msg;
@property (nonatomic, strong) NSArray *data;
@end
@interface SHYProductItem : SHYJastor
@property (nonatomic, strong) NSString *title;
@end
@implementation SHYProduct
+ (Class)dataClass//data;
{
return [SHYProductItem class];
}
- (void)dealloc
{
_msg = nil;
_data = nil;
}
@end
@implementation SHYProductItem
- (void)dealloc
{
_title = nil;
}
@end
外部用は便利です.コードは次のとおりです.
NSString *json = @"{\"code\":\"200\",\"msg\":\"\u83b7\u53d6\u6210\u529f\",\"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] initWithDictionary:body];
Modelがもっと上手に書けば、data属性をitemsに変更することができます.コードは以下の通りです.
@interface SHYProduct : SHYJastor
@property (nonatomic, assign) int code;
@property (nonatomic, strong) NSString *msg;
@property (nonatomic, strong) NSArray *items;
@end
@interface SHYProductItem : SHYJastor
@property (nonatomic, strong) NSString *title;
@end
@implementation SHYProduct
+ (Class)itemsClass//items;
{
return [SHYProductItem class];
}
- (void)dealloc
{
_msg = nil;
_items = nil;
}
- (NSDictionary *)mapping
{
NSMutableDictionary *maps = [NSMutableDictionary dictionaryWithDictionary:[super mapping]];
[maps setObject:@"data" forKey:@"items"];// ,
return maps;
}
@end
@implementation SHYProductItem
- (void)dealloc
{
_title = nil;
}
@end
見たでしょう、便利でしょう、体力の仕事はさようなら