键值编码KVC

许多编程技术都基于间接机制,包括整个面向对象编程领域。本章将介绍另一种间接机制,这种机制不属于Obj-C语言的特性,而是Cocoa提供的一种特性。

我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象。其实由于ObjC的语言特性,你根本不必进行任何操作就可以进行属性的动态读写,这种方式就是Key Value Coding(简称KVC)。

一些更加高级的Cocoa特性,例如Core Data和Cocoa Bindings(本书将不介绍该内容),在基础机制中包含了KVC。

KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说ObjC中几乎所有的对象都支持KVC操作。

Object-c

常用的KVC操作方法

动态设置

  1. - (void)setValue:(nullable id)value forKey:(NSString *)key;(用于简单路径)
  2. - (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)
  3. - (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;(用于字典传入,大数据赋值)

动态读取

  1. - (nullable id)valueForKey:(NSString *)key;(简单路径取值)
  2. - (nullable id)valueForKeyPath:(NSString *)keyPath;(复合路径取值)
  3. - (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;(批量取值,可以一致性提取多个数据)

例子

模型数据

Address.h

//
//  Address.h
//  KVC
//
//  Created by yangjun on 15/10/10.
//  Copyright © 2015年 六月. All rights reserved.
//

#import <Foundation/Foundation.h>

/** 地址*/
@interface Address : NSObject

@property (nonatomic, copy) NSString *addressName;///< 地址名

@end

User.h

//
//  User.h
//  KVC
//
//  Created by yangjun on 15/10/10.
//  Copyright © 2015年 六月. All rights reserved.
//

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

/** 用户*/
@interface User : NSObject

@property (nonatomic, copy) NSString *userName; ///< 用户名
@property (nonatomic, strong) Address *address; ///< 用户地址

@end

XCTestCase测试

//
//  KVCTests.m
//  KVCTests
//
//  Created by yangjun on 15/10/10.
//  Copyright © 2015年 六月. All rights reserved.
//

#import <XCTest/XCTest.h>
#import "User.h"

@interface KVCTests : XCTestCase
{
    User *_user;
}

@end

@implementation KVCTests

- (void)setUp {
    [super setUp];
    _user = [[User alloc] init];
}

- (void)testExample {

    // 简单路径
    [_user setValue:@"yangjun" forKey:@"userName"];
    NSString *value = [_user valueForKey:@"userName"];
    Address *address = [[Address alloc] init];
    address.addressName = @"BeiJing";
    [_user setValue:address forKey:@"address"];
    value = [_user valueForKey:@"userName"];
    NSLog(@"用户名:%@;地址:%@", _user.userName, _user.address.addressName);

    // 复合路径
    [_user setValue:@"君" forKeyPath:@"userName"];
    [_user setValue:@"北京" forKeyPath:@"address.addressName"];
    value = [_user valueForKeyPath:@"address.addressName"];
    NSLog(@"用户名:%@;地址:%@", _user.userName, _user.address.addressName);

    // 字典传入
    address = [[Address alloc] init];
    address.addressName = @"北京站";
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"阳", @"userName", address, @"address", nil];
    [_user setValuesForKeysWithDictionary:dict];// 设值
    dict  = [_user dictionaryWithValuesForKeys:[NSArray arrayWithObjects:@"userName", @"address", nil]];// 取值
    NSLog(@"用户名:%@;地址:%@", _user.userName, _user.address.addressName);
    NSLog(@"%@", dict);

}

@end

输出

2015-10-10 13:51:17.453 KVC[8450:699448] 用户名:yangjun;地址:BeiJing
2015-10-10 13:51:59.677 KVC[8450:699448] 用户名:君;地址:北京
2015-10-10 13:51:59.677 KVC[8450:699448] 用户名:阳;地址:北京站
2015-10-10 13:51:59.677 KVC[8450:699448] {
    address = "<Address: 0x7faf33439680>";
    userName = "\U9633";
}

Swift

常用KVC操作方法

动态设置

  1. setValue(value: AnyObject?, forKey key: String)(用于简单路径)
  2. setValue(value: AnyObject?, forKeyPath keyPath: String)(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)
  3. setValuesForKeysWithDictionary(keyedValues: [String : AnyObject]);(用于字典传入,大数据赋值)

动态读取

  1. valueForKey(key: String) -> AnyObject?(简单路径取值)
  2. valueForKeyPath(keyPath: String) -> AnyObject?(复合路径取值)
  3. dictionaryWithValuesForKeys(keys: [String]) -> [String : AnyObject](批量取值,可以一致性提取多个数据)

例子

模型数据

User.swift

import Foundation

/// 用户
class User: NSObject {

    /// 用户名
    dynamic var userName:String?

    override init() {
        userName = ""
    }

}

XCTestCase测试

//
//  KVCTests.swift
//  KVCTests
//
//  Created by yangjun on 15/10/10.
//  Copyright © 2015年 六月. All rights reserved.
//

import XCTest
@testable import KVC

/// KVC测试
class KVCTests: XCTestCase {

    /// 用户
    var user:User!;

    // MARK: 开始
    override func setUp() {
        super.setUp()
        self.user = User()
    }

    func testExample() {
        // 简单路径
        self.user.setValue("yangj", forKey:"userName") // 传值
        var value = self.user.valueForKey("userName") as? String // 取值
        print("\(value)")

        // 复合路径
        self.user.setValue("阳", forKeyPath: "userName")
        value = self.user.valueForKeyPath("userName") as? String
        print("\(value)")

        // 字典
        let dict = ["userName":"阳君"]
        self.user.setValuesForKeysWithDictionary(dict)
        let dictOut = self.user.dictionaryWithValuesForKeys(["userName"])
        print("\(dictOut)")
    }

}

输出

Optional("yangj")
Optional("阳")
["userName": 阳君]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值