7

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

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

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

  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Earl Grey
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit ExceededremoveProxyItemsObserver:Error: User Rate Limit Exceeded

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

    от joerick
  • 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 прокси-геттер.

  • 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
    

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