一.KVC的基本概念
Key-value coding,它是一种使用字符串标识符,间接访问对象属性的机制,而不是直接调用getter 和 setter方法。通常我们使用valueForKey 来替代getter 方法,setValue:forKey来代替setter方法。
下面,给大家一个例子,基础流程是这样的:
首先,创建基类,主要方法:
//根据这个来把key-value 自动分配到对应的属性
- (id) initWithDictionary:(NSMutableDictionary *) jsonObject;
然后,创建model类,继承自基类
model类需要实现方法
//如果遇到字典的key与model类中的属性名称不对应的情况,需要自己处理
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
//一般的赋值,key与model类中的属性名相同,处理一些特殊逻辑
- (void)setValue:(id)value forKey:(NSString *)key
各位还是通过代码来看下吧:
基类:JSONModel.h
//
// JSONModel.h
// iHotelApp_Demo
//
// Created by Eric on 14-1-13.
// Copyright (c) 2014年 Eric. All rights reserved.
//
#import
@interface JSONModel : NSObject
{
}
- (id) initWithDictionary:(NSMutableDictionary *) jsonObject;
@end
//
// JSONModel.m
// iHotelApp_Demo
//
// Created by Eric on 14-1-13.
// Copyright (c) 2014年 Eric. All rights reserved.
//
#import "JSONModel.h"
@implementation JSONModel
//根据字典初始化
- (id)initWithDictionary:(NSMutableDictionary *)jsonObject
{
self = [super init];
if (self)
{
[self setValuesForKeysWithDictionary:jsonObject];
}
return self;
}
//允许编码
- (BOOL) allowsKeyedCoding
{
return YES;
}
- (id) initWithCoder:(NSCoder *)aDecoder
{
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
//do nothing
}
//复制一个副本
- (id)mutableCopyWithZone:(NSZone *)zone
{
JSONModel *newModel = [[JSONModel allocWithZone:zone] init];
return newModel;
}
//复制一个副本
- (id)copyWithZone:(NSZone *)zone
{
JSONModel *newModel = [[[self class] allocWithZone:zone] init];
return newModel;
}
//找未找到的Key
- (id) valueForUndefinedKey:(NSString *)key
{
NSLog(@"Undefined Key: %@",key);
return nil;
}
//设置未找到的Key
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
NSLog(@"Undefined Key: %@",key);
}
@end
//
// MenuItem.h
// iHotelApp_Demo
//
// Created by Eric on 14-1-14.
// Copyright (c) 2014年 Eric. All rights reserved.
//
#import "JSONModel.h"
#import
/*
"id": "JAP122",
"image": "http://d1.myhotel.com/food_image1.jpg",
"name": "Teriyaki Bento",
"spicyLevel": 2,
"rating" : 4,
"description" : "Teriyaki Bento is one of the best lorem ipsum dolor sit",
"waitingTime" : "930",
"reviewCount" : 4
*/
@interface MenuItem : JSONModel
@property (nonatomic,strong) NSString *itemId;
@property (nonatomic,strong) NSString *image;
@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) NSString *spicyLevel;
@property (nonatomic,strong) NSString *rating;
@property (nonatomic,strong) NSString *itemDescription;
@property (nonatomic,strong) NSString *waitingTime;
@property (nonatomic,strong) NSString *reviewCount;
@property (nonatomic,strong) NSMutableArray *reviews;
@end
MenuItem 自定义实现解码,编码的方法,这样,基类JSONModel中的
initWithDictionary方法,便可以实现key-value与类属性的相对应
//
// MenuItem.m
// iHotelApp_Demo
//
// Created by Eric on 14-1-14.
// Copyright (c) 2014年 Eric. All rights reserved.
//
#import "MenuItem.h"
#import "Review.h"
@implementation MenuItem
- (id)init
{
self = [super init];
if (self) {
self.reviews = [NSMutableArray array];
}
return self;
}
//在赋值的过程中,如果发现未声明的Key
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
if ([key isEqualToString:@"id"]) {
self.itemId = value;
} else if([key isEqualToString:@"description"]){
self.itemDescription = value;
}else{
[super setValue:value forUndefinedKey:key];
}
}
//赋值
- (void)setValue:(id)value forKey:(NSString *)key
{
if ([key isEqualToString:@"reviews"]) {
for (NSMutableDictionary *reviewArrayDic in value) {
Review *thisReview = [[Review alloc] initWithDictionary:reviewArrayDic];
[self.reviews addObject:thisReview];
}
}else{
[super setValue:value forKey:key];
}
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.itemId forKey:@"itemId"];
[aCoder encodeObject:self.image forKey:@"image"];
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.spicyLevel forKey:@"spicyLevel"];
[aCoder encodeObject:self.rating forKey:@"rating"];
[aCoder encodeObject:self.itemDescription forKey:@"itemDescription"];
[aCoder encodeObject:self.waitingTime forKey:@"waitingTime"];
[aCoder encodeObject:self.reviewCount forKey:@"reviewCount"];
[aCoder encodeObject:self.reviews forKey:@"reviews"];
}
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if (self) {
self.itemId = [decoder decodeObjectForKey:@"itemId"];
self.image = [decoder decodeObjectForKey:@"image"];
self.name = [decoder decodeObjectForKey:@"name"];
self.spicyLevel = [decoder decodeObjectForKey:@"spicyLevel"];
self.rating = [decoder decodeObjectForKey:@"rating"];
self.itemDescription = [decoder decodeObjectForKey:@"itemDescription"];
self.waitingTime = [decoder decodeObjectForKey:@"waitingTime"];
self.reviewCount = [decoder decodeObjectForKey:@"reviewCount"];
self.reviews = [decoder decodeObjectForKey:@"reviews"];
}
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
id theCopy = [[[self class] allocWithZone:zone] init]; // use designated initializer
[theCopy setItemId:[self.itemId copy]];
[theCopy setImage:[self.image copy]];
[theCopy setName:[self.name copy]];
[theCopy setSpicyLevel:[self.spicyLevel copy]];
[theCopy setRating:[self.rating copy]];
[theCopy setItemDescription:[self.itemDescription copy]];
[theCopy setWaitingTime:[self.waitingTime copy]];
[theCopy setReviewCount:[self.reviewCount copy]];
[theCopy setReviews:[self.reviews copy]];
return theCopy;
}
@end
RESTfulEngine.m
//根据dict得到MenuItem实例
[[MenuItem alloc] initWithDictionary:obj]
- (RESTfulOperation *)fetchMenuItemsOnSucceeded:(ArrayBlock)succeedBlock onError:(ErrorBlock)errorBlock
{
RESTfulOperation *op = (RESTfulOperation *)[self operationWithPath:MENU_ITEMS_URL];
[op onCompletion:^(MKNetworkOperation *completedOperation) {
//得到返回的JSON字符串
NSMutableDictionary *responseDictionary = [completedOperation responseJSON];
//得到字符串中的menuitems的子节点的内容
NSMutableArray *menuItemsJson = [responseDictionary objectForKey:@"menuitems"];
NSMutableArray *menuItems = [NSMutableArray array];
//遍历节点,
[menuItemsJson enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//然后将其中的key-value 通过 initWithDictionary 给类的属性赋值
[menuItems addObject:[[MenuItem alloc] initWithDictionary:obj]];
}];
succeedBlock(menuItems);
} onError:errorBlock];
[self enqueueOperation:op];
return op;
}