Как добавить наблюдателя в NSMutableArray? - программирование
Подтвердить что ты не робот

Как добавить наблюдателя в NSMutableArray?

Я много искал, но не нашел полезного кода или учебника.

В моем приложении у меня есть изменяемый массив, который обновляется каждые 60 секунд.

Объекты в массиве отображаются в виде табличного представления в нескольких диспетчерах представления.

Я хочу перезагрузить табличное представление автоматически, когда только когда значения в массиве изменяются или обновляются.

Для этого я хочу добавить наблюдателя в изменяемый массив, то есть когда значения в массиве меняются, тогда он должен вызывать конкретный метод, например,

-(void)ArrayUpdatedNotification:(NSMutableArray*)array
{
    //Reload table or do something
} 

Спасибо заранее.

4b9b3361

Ответ 1

Что может быть сделано - после обновления вашего массива отправьте уведомление (NSNotificationCenter), и это уведомление будет получено всеми контроллерами. При получении notificaiton контроллер должен выполнять [tableview reloaddata].

Пример кода:

// Adding an observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateTable:) name:@"arrayUpdated" object:nil];

// Post a notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"arrayUpdated" object:nil]; 

// the void function, specified in the same class where the Notification addObserver method has defined
- (void)updateTable:(NSNotification *)note { 
    [tableView reloadData]; 
}

Ответ 2

Вы можете абстрагировать массив в класс контейнера данных с помощью методов доступа, а затем использовать наблюдение за ключевым значением, чтобы наблюдать, когда массив, который поддерживает объект контейнера, изменяется (вы не можете напрямую использовать KVO на NSArray).

Далее следует простой пример класса, используемого как абстракция поверх массива. Вы используете его методы insertObject:inDataAtIndex: и removeObjectFromDataAtIndex: вместо прямого доступа к параметрам с addObject: и removeObject:.

// DataContainer.h
@interface DataContainer : NSObject

// Convenience accessor
- (NSArray *)currentData;

// For KVC compliance, publicly declared for readability
- (void)insertObject:(id)object inDataAtIndex:(NSUInteger)index;
- (void)removeObjectFromDataAtIndex:(NSUInteger)index;
- (id)objectInDataAtIndex:(NSUInteger)index;
- (NSArray *)dataAtIndexes:(NSIndexSet *)indexes;
- (NSUInteger)countOfData;

@end

// DataContainer.m

@interface DataContainer ()

@property (nonatomic, strong) NSMutableArray *data;

@end

@implementation DataContainer

//  We'll use automatic notifications for this example
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
{
    if ([key isEqualToString:@"data"]) {
        return YES;
    }
    return [super automaticallyNotifiesObserversForKey:key];
}

- (id)init
{
    self = [super init];
    if (self) {
        // This is the ivar which provides storage
        _data = [NSMutableArray array];
    }
    return self;
}

//  Just a convenience method
- (NSArray *)currentData
{
    return [self dataAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self countOfData])]];
}

//  These methods enable KVC compliance
- (void)insertObject:(id)object inDataAtIndex:(NSUInteger)index
{
    self.data[index] = object;
}

- (void)removeObjectFromDataAtIndex:(NSUInteger)index
{
    [self.data removeObjectAtIndex:index];
}

- (id)objectInDataAtIndex:(NSUInteger)index
{
    return self.data[index];
}

- (NSArray *)dataAtIndexes:(NSIndexSet *)indexes
{
    return [self.data objectsAtIndexes:indexes];
}

- (NSUInteger)countOfData
{
    return [self.data count];
}

@end

Причина, по которой мы это делаем, - это теперь мы можем наблюдать изменения, внесенные в базовый массив. Это делается с помощью Key Value Observing. Отображается простой контроллер представлений, который создает экземпляр и наблюдает за контроллером данных:

// ViewController.h
@interface ViewController : UIViewController

@end

// ViewController.m

@interface ViewController ()

@property (nonatomic,strong) DataContainer *dataContainer;

@end

@implementation ViewController

static char MyObservationContext;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        //  Instantiate a DataContainer and store it in our property
        _dataContainer = [[DataContainer alloc] init];
        //  Add self as an observer. The context is used to verify that code from this class (and not its superclass) started observing.
        [_dataContainer addObserver:self
                         forKeyPath:@"data"
                            options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew)
                            context:&MyObservationContext];
    }

    return self;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    //  Check if our class, rather than superclass or someone else, added as observer
    if (context == &MyObservationContext) {
        //  Check that the key path is what we want
        if ([keyPath isEqualToString:@"data"]) {
            //  Verify we're observing the correct object
            if (object == self.dataContainer) {
                NSLog(@"KVO for our container property, change dictionary is %@", change);
            }
        }
    }
    else {
        //  Otherwise, call up to superclass implementation
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    //  Insert and remove some objects. Console messages should be logged.
    [self.dataContainer insertObject:[NSObject new] inDataAtIndex:0];
    [self.dataContainer insertObject:[NSObject new] inDataAtIndex:1];
    [self.dataContainer removeObjectFromDataAtIndex:0];
}

- (void)dealloc
{
    [_dataContainer removeObserver:self forKeyPath:@"data" context:&MyObservationContext];
}

@end

Когда этот код запускается, три изменения данных наблюдаются контроллером представления и регистрируются на консоли:

KVO for our container property, change dictionary is {
        indexes = "<NSIndexSet: 0x8557d40>[number of indexes: 1 (in 1 ranges), indexes: (0)]";
        kind = 2;
        new =     (
            "<NSObject: 0x8557d10>"
        );
    }
KVO for our container property, change dictionary is {
        indexes = "<NSIndexSet: 0x715d2b0>[number of indexes: 1 (in 1 ranges), indexes: (1)]";
        kind = 2;
        new =     (
            "<NSObject: 0x71900c0>"
        );
    }
KVO for our container property, change dictionary is {
        indexes = "<NSIndexSet: 0x8557d40>[number of indexes: 1 (in 1 ranges), indexes: (0)]";
        kind = 3;
        old =     (
            "<NSObject: 0x8557d10>"
        );
    }

Хотя это несколько сложный (и может быть гораздо более активным), это единственный способ автоматического уведомления о том, что измененное содержимое массива было изменено.

Ответ 3

Если вы хотите использовать блестящие блоки, вы можете сделать это

// Create an instance variable for your block holder in your interface extension
@property (strong) id notificationHolder;

// Listen for notification events (In your TableView class.
self.notificationHolder = [[NSNotificationCenter defaultCenter] addObserverForName:@"NotificationName"
                             object:nil
                              queue:[NSOperationQueue mainQueue]
                         usingBlock:^(NSNotification *note) {

        NSLog(@"Received notification");
}];

Затем в dealloc (или когда вы больше не используете его)

- (void)dealloc {
     [[NSNotificationCenter defaultCenter] removeObserver:self.notificationHolder];
}

Тогда в некотором другом классе

// Send a notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationName" object:nil];

Спросите, не ясно ли что-то! Надеюсь, это поможет!

ИЗМЕНИТЬ ИЗ КОММЕНТАРИИ

"YourEvent" - это имя уведомления, это означает, что вы можете назвать его так, как хотите. (Возможно, "UpdateArrayNotification может быть хорошим именем?)

Что-то задуматься: обратите внимание, что у вас может быть несколько наблюдателей за одно и то же уведомление. Это означает, что один "пост" будет расхватен всеми наблюдателями.