Вопрос по objective-c, ios – Наблюдение за количеством в NSMutableArray

7

Я хотел бы получать уведомления, когда счет, т.е. количество элементов в NSArray изменяется .. Конечно, мне бы это не понадобилось, если бы я контролировал добавление и удаление объектов в массиве. Но это не так, это непредсказуемо происходит в отношении модели бизнес-процесса и зависит от внешних факторов. Есть ли какое-то простое элегантное решение?

РЕДАКТИРОВАТЬ: я исправляю это к NSMutableArray конечно ..

Я не 100% на этом, но keyPath к массиву и суффиксу@count это KVC способ получить это значение. Так что, возможно, вы можете КВО наблюдать[email protected]? developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/… joerick

Ваш Ответ

2   ответа
6

Чтобы наблюдать изменения в mutableArray, нужно использовать изменяемый прокси-объект, заданный

 - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key

который является совместимым с KVO, т.е. любое изменение прокси-объекта отправляет / делает уведомления об изменении.

В следующем демонстрационном классе показана полная реализация

@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:@"[email protected]" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}

- (void)removeItemsObserver:(id)object
{
    [self removeObserver:object forKeyPath:@"[email protected]" 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

Теперь каждый раз, когда вы добавляете или удаляете объект вitems вы увидите новый лог в консоли (observeValueForKeyPath называется).

Любое прямое изменение автосинтезированного ивара_itemsмассив не будет иметь никакого эффекта.

Также обратите внимание, что вам настоятельно необходимо установить наблюдателя на[email protected] (наблюдения[email protected] бессмысленно).

Обратите внимание, что вам не нужно инициализировать_items или жеself.items, Это будет сделано за кулисами, когда вы позвонитеitems добытчик.

Каждый раз, когда вы изменяете «массив»items вы получите новый объект_items с новым адресом. Но я все еще могу найти его черезitems прокси-геттер.

Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededremoveProxyItemsObserver:Error: User Rate Limit Exceeded
15

Вам нужно будет использоватьКВЦ, Но как это сделать? В конце концов, NSMutableArray не совместим с Key-Value-Coding для своих методов мутации или изменений содержимого. Ответ заключается в проксировании, поскольку создание подкласса NS [Mutable] Array - слишком сложная задача.

NSProxy - это отличный маленький класс, который вы можете использовать для перехвата сообщений, отправляемых в ваш массив, как если бы вы были 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

Если у вас нет возможности обернуть массив таким образом, попробуйте переосмыслить свой код. Если внешняя зависимость загоняет вас в такой угол, попробуйте удалить его. Работать с собственными инструментами всегда плохо.

Error: User Rate Limit Exceeded Earl Grey
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы