Подтвердить что ты не робот

Пример 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.

4b9b3361

Ответ 1

Вы не можете наблюдать массив для изменений. 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

Ответ 2

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

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];

Edit: Чтобы сделать все более ясным, поместите имя своего массива вместо свойства. Например:

lazy var widgets:NSMutableArray = NSMutableArray()
let signal = self.rac_valuesAndChangesForKeyPath("widgets", options:      NSKeyValueObservingOptions.New | NSKeyValueObservingOptions.Old, observer:self)