第十四章 REST解惑——初识KVC

一.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 <Foundation/Foundation.h>

@interface JSONModel : NSObject<NSCopying,NSCoding,NSMutableCopying>
{

}

- (id) initWithDictionary:(NSMutableDictionary *) jsonObject;

@end

JSONModel.m

//
//  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    JSONModel的子类。

//
//  MenuItem.h
//  iHotelApp_Demo
//
//  Created by Eric on 14-1-14.
//  Copyright (c) 2014年 Eric. All rights reserved.
//

#import "JSONModel.h"
#import <Foundation/Foundation.h>


/*
 "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.m

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;
}

Demo 下载地址:iHotelAPP

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值