1

我在我的收藏中添加了一个观察者,并观察它的计数

[[[JHTaskSave defaults] tasks] addObserver:self forKeyPath:@"count" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

JHTaskSave 是一个单例对象,而 tasks 是一个 JHTaskCollection KVC 兼容,当我将一个对象添加到我的集合时:

[[[JHTaskSave defaults] tasks] addTask:newTask]

任务数发生变化但没有调用observeValueForKeyPath,我不明白为什么

这是我的收藏类:

@interface JHTaskCollection : NSObject <NSFastEnumeration>
{
    NSMutableArray      *_tasks;
}

@property (nonatomic) NSUInteger count;

- (id)taskAtIndex:(NSUInteger)index;
- (void)addTask:(JHTask *)task;
- (void)removeTask:(JHTask *)task;
- (void)insertObject:(id)key inTasksAtIndex:(NSUInteger)index;
- (void)removeObjectFromTasksAtIndex:(NSUInteger)index;
- (void)removeTaskAtIndexes:(NSIndexSet *)indexes;
- (NSArray *)taskAtIndexes:(NSIndexSet *)indexes;

@end


@implementation JHTaskCollection

- (id)init
{
    if(self = [super init]) {
        _tasks = [[NSMutableArray alloc] init];
    }
    return self;
}

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len
{
    return [_tasks countByEnumeratingWithState:state objects:stackbuf count:len];
}

- (NSArray *)taskAtIndexes:(NSIndexSet *)indexes
{
    return [_tasks objectsAtIndexes:indexes];
}

- (void)insertObject:(id)key inTasksAtIndex:(NSUInteger)index
{
    [_tasks insertObject:key atIndex:index];
}

- (void)removeObjectFromTasksAtIndex:(NSUInteger)index
{
    [_tasks removeObjectAtIndex:index];
}

- (void)removeTaskAtIndexes:(NSIndexSet *)indexes
{
    [_tasks removeObjectsAtIndexes:indexes];
}

- (JHTask *)taskAtIndex:(NSUInteger)index
{
    return [_tasks objectAtIndex:index];
}

- (NSUInteger)count
{
    return _tasks.count;
}

- (void)addTask:(JHTask *)task
{
    [_tasks addObject:task];
}

- (void)removeTask:(JHTask *)task
{
    [_tasks removeObject:task];
}

@end
4

3 回答 3

1

根据您发布的代码,如果您想count成为 Key-Value Observable,您需要在任何时候以改变计数的方式改变集合时发送willChangeValueForKey和通知。didChangeValueForKey使用您的代码:

@implementation JHTaskCollection

- (id)init
{
    if(self = [super init]) {
        _tasks = [[NSMutableArray alloc] init];
    }
    return self;
}

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len
{
    return [_tasks countByEnumeratingWithState:state objects:stackbuf count:len];
}

- (NSArray *)taskAtIndexes:(NSIndexSet *)indexes
{
    return [_tasks objectsAtIndexes:indexes];
}

- (void)insertObject:(id)key inTasksAtIndex:(NSUInteger)index
{
    [self willChangeValueForKey: @"count"];
    [_tasks insertObject:key atIndex:index];
    [self didChangeValueForKey: @"count"];
}

- (void)removeObjectFromTasksAtIndex:(NSUInteger)index
{
    [self willChangeValueForKey: @"count"];
    [_tasks removeObjectAtIndex:index];
    [self didChangeValueForKey: @"count"];
}

- (void)removeTaskAtIndexes:(NSIndexSet *)indexes
{
    [self willChangeValueForKey: @"count"];
    [_tasks removeObjectsAtIndexes:indexes];
    [self didChangeValueForKey: @"count"];
}

- (JHTask *)taskAtIndex:(NSUInteger)index
{
    return [_tasks objectAtIndex:index];
}

- (NSUInteger)count
{
    return _tasks.count;
}

- (void)addTask:(JHTask *)task
{
    [self willChangeValueForKey: @"count"];
    [_tasks addObject:task];
    [self didChangeValueForKey: @"count"];
}

- (void)removeTask:(JHTask *)task
{
    [self willChangeValueForKey: @"count"];
    [_tasks removeObject:task];
    [self didChangeValueForKey: @"count"];
}

@end
于 2013-08-03T19:53:07.873 回答
0

没有触发通知的原因有count两个,都与键值编码有关。

第一个原因是因为count调用时属性没有更新addTask:count属性和 _tasks 数组的计数之间没有直接联系。任何操作数组的代码都必须在-willChangeValueForKey:-didChangeValueForKey:调用之间进行包装。然而,KVO 协议提供了设置依赖键的能力。由于 count 属性受数组影响,因此您可以通过使用设置这两个键之间的依赖关系

+ (NSSet*) keyPathsForValuesAffectingCount {
  return [NSSet setWithObject:@"tasks"];
}

或者更通用的+ keyPathsForValuesAffectingValueForKey:(NSString *)key。实施其中任何一个都会触发count修改时间tasks的通知。

这不起作用的第二个原因是因为您没有按照Key-Value Coding Programming Guidetasks中定义的符合 Key-Value 的方式更新数组。基本上,有序集合中的对象必须添加

-insertObject:in<Key>AtIndex:
-insert<Key>:atIndexes:

或者被will|didChangeValueForKey:电话包裹。

在您的示例中,如果您在设置关键依赖项后提供以下实现,您应该观察到变化。

- (void)addTask:(JHTask *)task
{
  [self insertObject:task inTasksAtIndex:[_tasks count]];
}
于 2013-06-28T18:43:18.130 回答
-2

-(NSInteger) count是一种方法,因此,您不能使用 KVO 来监视它 - 您可以使用AOP,尽管我认为这不是您想要的方向。

也许相反,您可以直接监视集合,而不是计数,尽管我不确定您是否可以使用 KVO 执行此操作(我认为您不能) - 您需要添加一个 addObject: 方法并执行您的里面有魔法?

编辑:

您可以使用此博客中所述的“方法调配”,但值得增加晦涩难懂吗?

于 2013-06-03T12:42:16.210 回答