对于
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
- 注意使用KVO, 必须要在适当的位置移除观察者, 且
keypath
不建议使用字符串. 可以使用@selector
之类的小技巧.
网友评论