在IOS中都有一种双向绑定机制,如果数据模型修改了之后会立即反映到UI视图上,它叫做Key Value Observing(简称KVO)。KVO其实是一种观察者模式,利用它可以很容易实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器的视图组件就会被激发,激发时就会回调监听器自身。
在ObjC中要实现KVO则必须实现NSKeyValueObServing协议,不过幸运的是NSObject已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO。
Object-C
在ObjC中使用KVO操作常用的方法如下:
1. 注册指定Key路径的监听器: addObserver: forKeyPath: options: context:
2. 删除指定Key路径的监听器: removeObserver: forKeyPath、removeObserver: forKeyPath: context:
3. 回调监听: observeValueForKeyPath: ofObject: change: context:
KVO的使用步骤也比较简单:
1.通过addObserver: forKeyPath: options: context:为被监听对象(它通常是数据模型)注册监听器
2.重写监听器的observeValueForKeyPath: ofObject: change: context:方法
模型数据
User.h
//
// User.h
// KVO
//
// Created by yangjun on 15/10/10.
// Copyright © 2015年 六月. All rights reserved.
//
#import <Foundation/Foundation.h>
/** 用户*/
@interface User : NSObject
@property (nonatomic, copy) NSString *userName; ///< 用户名
@end
XCTestCase测试
//
// KVOTests.m
// KVOTests
//
// Created by yangjun on 15/10/10.
// Copyright © 2015年 六月. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "User.h"
@interface KVOTests : XCTestCase
{
User *_user;
}
@end
@implementation KVOTests
- (void)setUp {
[super setUp];
_user = [[User alloc] init];
[_user addObserver:self forKeyPath:@"userName" options:NSKeyValueObservingOptionNew context:nil];// 添加监听
}
- (void)tearDown {
[super tearDown];
_user = nil;
}
- (void)testExample {
_user.userName = @"yangjun";
[_user removeObserver:self forKeyPath:@"userName"];// 取消监听
_user.userName = @"IOS";
}
#pragma mark 监听
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([@"userName" isEqualToString:keyPath]) {// 这里只处理userName属性
NSLog(@"userName:%@; change:%@", ((User *)object).userName, change);
}
}
@end
输出
2015-10-10 15:23:47.660 KVO[10344:789286] userName:yangjun; change:{
kind = 1;
new = yangjun;
}
Swift
在Swift中使用KVO操作常用的方法如下:
1. 注册指定Key路径的监听器:addObserver(observer: NSObject, forKeyPath keyPath: String, options: NSKeyValueObservingOptions, context: UnsafeMutablePointer<Void>)
2. 删除指定Key路径的监听器:removeObserver(observer: NSObject, forKeyPath keyPath: String)
3. 回调监听:override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>)
KVO的使用步骤也比较简单:
1.通过addObserver: forKeyPath: options: context:为被监听对象(它通常是数据模型)注册监听器
2.重写监听器的observeValueForKeyPath: ofObject: change: context:方法
模型
User.swift
//
// User.swift
// KVO
//
// Created by yangjun on 15/10/10.
// Copyright © 2015年 六月. All rights reserved.
//
import Foundation
/// 用户
class User: NSObject {
/// 用户名
dynamic var userName:String?
override init() {
userName = ""
}
}
XCTestCase测试
//
// KVOTests.swift
// KVOTests
//
// Created by yangjun on 15/10/10.
// Copyright © 2015年 六月. All rights reserved.
//
import XCTest
/// KVO测试
class KVOTests: XCTestCase {
/// 用户
var user:User!;
// MARK: 开始
override func setUp() {
super.setUp()
self.user = User()
self.user.addObserver(self, forKeyPath: "userName", options: NSKeyValueObservingOptions.New, context: nil)// 监听(KVO的属性必须设置dynamic)
}
// MARK: 结束
override func tearDown() {
super.tearDown()
self.user.removeObserver(self, forKeyPath: "userName")
self.user.userName = "YangJun"
}
// MARK: 测试用例
func testExample() {
self.user.userName = "阳君"
}
// MARK: - 监听
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if "userName" == keyPath {
print("userName:\((object as? User)?.userName); change:\(change)")
}
}
}
输出
userName:Optional("阳君"); change:Optional(["new": 阳君, "kind": 1])