键值监听KVO

在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])

你可能感兴趣的:(ios,观察者模式,KVO)