天天看點

鍵值監聽KVOObject-CSwift

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