Objective c 在NSMutableArray中观察计数

Objective c 在NSMutableArray中观察计数,objective-c,ios,nsarray,Objective C,Ios,Nsarray,当计数(即NSArray中的项目数)发生变化时,我希望得到通知。。 当然,如果我能控制向数组中添加和删除对象,我就不需要这个了。但我不是,它发生在业务流程模型方面是不可预测的,并且取决于外部因素。 有一些简单优雅的解决方案吗 编辑:我正在将此更正为NSMutableArray,当然。您需要使用。但是如何着手去做呢?毕竟,NSMutableArray的变异方法或内容变化不符合键值编码。答案是代理——因为子类化NS[Mutable]数组太麻烦了 Nproxy是一个很好的小类,您可以使用它来截获发送到

当计数(即NSArray中的项目数)发生变化时,我希望得到通知。。 当然,如果我能控制向数组中添加和删除对象,我就不需要这个了。但我不是,它发生在业务流程模型方面是不可预测的,并且取决于外部因素。 有一些简单优雅的解决方案吗

编辑:我正在将此更正为NSMutableArray,当然。

您需要使用。但是如何着手去做呢?毕竟,NSMutableArray的变异方法或内容变化不符合键值编码。答案是代理——因为子类化NS[Mutable]数组太麻烦了

Nproxy是一个很好的小类,您可以使用它来截获发送到阵列的消息,就像截获NSMutableArray一样,然后将它们转发到某个内部实例。不幸的是,它也不符合KVC,因为KVC的核心存在于NSObject中。那我们就得用这个了。示例接口可能如下所示:

@interface CFIKVCMutableArrayProxy : NSObject  {
    NSMutableArray *_innerArray;
}

- (NSUInteger)count;

- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)addObject:(id)anObject;
- (void)removeLastObject;
- (void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;

//…

@end
如您所见,我们正在模拟
NSMutableArray
的接口,这是必要的,因为我们的代理应该实现一切,就像它是
NSMutableArray
一样。这也使得实现尽可能简单,因为我们可以将选择器转发到内部
NSMutableArray
指针上。为了简洁起见,我将只实现两种方法来向您展示一般大纲的外观:

@implementation CFIKVCMutableArrayProxy

//…

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

- (void)addObject:(id)anObject {
    [self willChangeValueForKey:@"count"];
    [_innerArray addObject:anObject];
    [self didChangeValueForKey:@"count"];
}

- (void)removeLastObject {
    [self willChangeValueForKey:@"count"];
    [_innerArray removeLastObject];
    [self didChangeValueForKey:@"count"];
}

@end

如果您没有机会像这样包装一个数组,那么请尝试重新思考您的代码。如果外部依赖迫使您进入这种困境,请尝试删除它。使用自己的工具总是一件坏事。

要观察可变数组中的变化,需要使用

 - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key
符合KVO,即代理对象的任何更改都会发送will/did更改通知

下面的演示类展示了完整的实现

@interface DemoClass : NSObject

@property (nonatomic) NSMutableArray *items;

- (void)addItemsObserver:(id)object;
- (void)removeItemsObserver:(id)object;

@end

@implementation DemoClass

- (NSMutableArray *)items;
{
    return [self mutableArrayValueForKey:@"_items"];
}

- (void)addItemsObserver:(id)object
{
    [self addObserver:object forKeyPath:@"_items.@count" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}

- (void)removeItemsObserver:(id)object
{
    [self removeObserver:object forKeyPath:@"_items.@count" context:nil];
}
@end


@interface ObservingClass : NSObject

@property (nonatomic) DemoClass *demoObject;

@end

@implementation ObservingClass

- (instanstype)init
{
     if (self = [super init]) {
         _demoObject = [DemoClass new];

         [_demoObject addItemsObserver:self];
     }
     return self;
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                  ofObject:(id)object
                    change:(NSDictionary *)change
                   context:(void *)context
{
     NSLog(@"is called on demoObject.items.count change");
}

- (void)dealloc
{
    [_demoObject removeItemsObserver:self];
}

@end
现在,每次在
项中添加或删除对象时,您都会在控制台中看到新的日志(
observeValueForKeyPath

自动合成ivar
\u项
数组的任何直接更改都不会产生任何影响

还请注意,您强烈需要在
\u项上设置观察者。@count
(观察
项。@count
没有意义)

请注意,您不需要初始化
\u items
self.items
。当您调用
items
getter时,它将在幕后完成


每次更改“数组”
items
时,您将获得新地址的新对象
\u items
。但是我仍然可以通过
items
代理getter找到它。

我不是100%了解它,而是数组的键路径和后缀
@count
是获取此值的KVC方法。因此,也许您可以观察KVO
array@count
?一段时间过去了,幸运的是,在我无法控制的代码部分将实现一个改进——保存数组的facade对象现在将在模型更改时发出通知。您提出的解决方案值得注意,但是您忽略了一个小而重要的事实,即我没有控制阵列。因此,我不可能将代理对象注入facade而不是数组。@CodaFi感谢您的解释:)您可能还需要一个
removeProxyItemsObserver:
方法。@AaronBrager,刚刚添加是为了完整性。谢谢。为什么不在示例代码中添加mutableArrayValueForKey的用法呢?这是很重要的一点!