Пример ReactiveCocoa с NSMutableArray push/pop?

Может ли кто-нибудь предоставить однострочный пример использования абстракций ReactiveCocoa для достижения чего-то вроде этого:

// pseudo-code
NSMutableArray *array = @[[] mutableCopy];
RACSignal *newValue = RACAbleWithStart(array); // get whole array or maybe just added/removed element on push/pop

[newValue subscribeNext:^(NSArray *x) {
  // x is whole array
}]

[newValue subscribeNext:^(id x) {
  // x is new value
}]

[newValue subscribeNext:^(id x) {
  // x is removed value
}]

Я вижу, что некоторые расширения для NSArray были удалены в пользу Mantle https://github.com/ReactiveCocoa/ReactiveCocoa/pull/130 Но все еще не могу найти простой пример манипуляции NSArray.

2 ответа

Решение

Вы не можете наблюдать массив для изменений. ReactiveCocoa использует наблюдение значения ключа. Который, как следует из названия, наблюдает только изменения ключевых атрибутов (членов словаря, свойств и т. Д.).

Что вы можете сделать, это наблюдать свойство массива для изменений:

@interface Blah : NSObject
@property (copy, readonly) NSArray *arrayProperty;
@end

// later...
Blah *blah = [Blah new];
[RACObserve(blah, arrayProperty) subscribeNext:^(NSArray *wholeArray){}];

Если вы хотите знать, какие объекты были вставлены / удалены, у вас есть два варианта. Вы можете решить это, сохранив каждый массив и сравнив каждый с предыдущим. Это самое простое, но плохо работает с очень большими массивами. AFAIK, ReactiveCocoa не имеет встроенных операций для этого.

Или вы можете реализовать средства доступа к коллекции KVO и убедиться, что изменения в массиве сделаны с использованием mutableArrayValueForKey:, Это позволяет избежать создания нового массива всякий раз, когда вносятся какие-либо изменения, а также уведомляет наблюдателей об изменениях, внесенных в прокси-массив, возвращаемый mutableArrayValueForKey:,

Наблюдение за информацией об изменениях с помощью ReactiveCocoa несколько сложнее:

RACSignal *changeSignal = [blah rac_valuesAndChangesForKeyPath:@keypath(blah, arrayProperty) options: NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld observer:nil];
[changeSignal subscribeNext:^(RACTuple *x){
    NSArray *wholeArray = x.first;
    NSDictionary *changeDictionary = x.second;
}];

Словарь изменений сообщает вам, какие изменения были внесены в массив, какие объекты были вставлены / удалены, а также индексы вставленных / удаленных объектов.

Он задокументирован по адресу: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSKeyValueObserving_Protocol/Reference/Reference.html

Быстрый эквивалент для решения Криса:

let signal = self.object.rac_valuesAndChangesForKeyPath("property", options:      NSKeyValueObservingOptions.New | NSKeyValueObservingOptions.Old, observer:self.object)
signal.subscribeNext { (object) -> Void in
   if let tuple = object as? RACTuple {
        var wholeArray = tuple.first as? NSArray
        var changeDictionary = tuple.second as? NSDictionary
    }
}

Также убедитесь, что вы изменили свойство содержимого в соответствии с требованиями KVO.

// This is wrong and wont send values to RAC signals
[self.contents addObject:object];

// This is correct and will send values to RAC signals
NSMutableArray *contents = [account mutableArrayValueForKey:@keypath(self, contents)];
[contents addObject:object];

Изменить: чтобы сделать вещи более понятными, поместите имя вашего массива вместо свойства. Например:

lazy var widgets:NSMutableArray = NSMutableArray()
let signal = self.rac_valuesAndChangesForKeyPath("widgets", options:      NSKeyValueObservingOptions.New | NSKeyValueObservingOptions.Old, observer:self)
Другие вопросы по тегам