[iOS] KVO监听数组

2018-04-30  本文已影响502人  manajay

对于swift,因为数组是值类型, 操作数组时,didSet 属性观察就可以很容易做到这一点.

对于Objective-C ,必须要使用 KVO 才能 监听数组, 而且一般的操作只能监听对象指针的改变, 指针所指向的内容变化却无从察觉.

#import "TodoStore.h"
#import "LJConst.h"
#import "TodosChangeNotifyInfo.h"

@interface TodoStore()
/**
 todo数据源
 */
@property (nonatomic, strong, readwrite) NSMutableArray<TodoItem *> *todos;
@end

@implementation TodoStore

#pragma mark - Life Circle
+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init {
    if (self = [super init]) {
        [self configData];
        [self configObserver];
    }
    return self;
}

- (void)configData {
    self.todos = [NSMutableArray arrayWithCapacity:5];
}

#pragma mark - KVO
- (void)configObserver {
    [self addObserver:self forKeyPath:NSStringFromSelector(@selector(todos)) options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld  context:nil];
}

- (void)dealloc {
    [self removeObserver:self forKeyPath: NSStringFromSelector(@selector(todos))];
}

///  相关键值描述见 [KVO](http://yulingtianxia.com/blog/2014/05/12/objective-czhong-de-kvche-kvo/)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    // 其余的情况暂时不考虑, 例如,new & old 为数组的情况
    
    // 增加的
    NSArray *new = [change valueForKey: NSKeyValueChangeNewKey];
    NSLog(@"new : %@", new);
    // 移除的
    NSArray *old = [change valueForKey: NSKeyValueChangeOldKey];
    NSLog(@"old : %@", old);

    // 变更的索引
    NSIndexSet *indexes = [change valueForKey: NSKeyValueChangeIndexesKey];
    NSLog(@"indexes: %@",indexes);
    
    // 变更的类型
    NSKeyValueChange kind = [[change valueForKey: NSKeyValueChangeKindKey] unsignedIntegerValue];
    NSLog(@"kind: %lu",kind);

    switch (kind) {
        case NSKeyValueChangeInsertion  :
            [self changgsPostNotificationWithChangeType: TodosChangeTypeAdd changeIndexSet:indexes];
            break;
        case NSKeyValueChangeRemoval    :
            [self changgsPostNotificationWithChangeType: TodosChangeTypeRemove changeIndexSet:indexes];
            break;
        case NSKeyValueChangeSetting    :
            
            break;
        case NSKeyValueChangeReplacement:
            [self changgsPostNotificationWithChangeType: TodosChangeTypeReload changeIndexSet:indexes];
            break;
    }
    
}

- (void)changgsPostNotificationWithChangeType:(TodosChangeType) changeType changeIndexSet: (NSIndexSet *) changeIndexSet{
    TodosChangeNotifyInfo *notifyInfo = [TodosChangeNotifyInfo new];
    notifyInfo.changeType     = changeType;
    notifyInfo.changeIndexSet = changeIndexSet;
    
    NSDictionary *userInfo = @{kUserInfoNotifyInfoKey: notifyInfo};
    
    [[NSNotificationCenter defaultCenter] postNotificationName:kTodosChangeNotificationName object:nil userInfo:userInfo];
}

#pragma mark - Action
- (void)addItems:(NSArray<TodoItem *> *)todoItems {
    [[self kvcTodos] addObjectsFromArray:todoItems];
}

- (void)addItem:(TodoItem *)todoItem {
    [[self kvcTodos] addObject:todoItem];
}

- (void)removeItems:(NSArray<TodoItem *> *)todoItems {
    [[self kvcTodos] removeObjectsInArray:todoItems];
}

- (void)removeItem:(TodoItem *)todoItem {
    [[self kvcTodos] removeObject:todoItem];
}

- (void)removeItemAtIndex:(NSUInteger)index {
    [[self kvcTodos] removeObjectAtIndex:index];
}

- (void)editItem:(TodoItem *)original new:(TodoItem *)new {
    NSUInteger index = [[self kvcTodos] indexOfObject:original];
    [self kvcTodos][index] = new;
}

#pragma mark - 只读

- (NSUInteger)count{
    return self.todos.count;
}

- (NSArray<TodoItem *> *)todoItems {
    return self.todos.copy;
}

- (TodoItem *)todoAtIndex:(NSUInteger)index {
    return self.todos[index];
}


/**
 只用于内部KVO监听
 通过KVC获取数组,可以触发KKVO监听
 @return todo数组
 */
- (NSMutableArray<TodoItem *> *)kvcTodos {
    return [self mutableArrayValueForKeyPath:NSStringFromSelector(@selector(todos))];
}

@end

源码见 manajay/iOS-demos/MVC-onevcat

上一篇下一篇

猜你喜欢

热点阅读