Как быть уведомленным относительно изменений в моделях через NSArrayController?

Используйте функцию Intn из пакета rand для выбора случайного индекса.

import (
  "math/rand"
  "time"
)

// ...

rand.Seed(time.Now().Unix()) // initialize global pseudo random generator
message := fmt.Sprint("Gonna work from home...", reasons[rand.Intn(len(reasons))])

Другим решением является использование объекта Rand.

s := rand.NewSource(time.Now().Unix())
r := rand.New(s) // initialize local pseudorandom generator 
r.Intn(len(reasons))

8
задан Quinn Taylor 30 June 2009 в 19:49
поделиться

2 ответа

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

Я думаю, что документацию по ключевым путям можно улучшить, потому что я ничего не мог найти это объяснило очень простое изменение, которое мне нужно было сделать. Есть полезная информация о магических путях для ключей в массиве, но нет простой документации «это обычные вещи»

В любом случае. Ранее в моем подклассе NSView у меня было следующее:

- (void) bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
  if ([binding isEqualToString:@"observedObjects"]) {
    [observable addObserver:self forKeyPath:@"arrangedObjects" options:0 context:nil];
  } else {
    [super bind:binding toObject:observable withKeyPath:keyPath options:options];
  }
}

Все, что мне нужно было добавить, чтобы получать уведомления об изменениях в моделях в NSArrayController , schemeObjects , так это наблюдение за arrayObjects.name (для name свойство моей модели). Таким образом, приведенный выше код стал:

- (void) bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
  if ([binding isEqualToString:@"observedObjects"]) {
    [observable addObserver:self forKeyPath:@"arrangedObjects" options:0 context:nil];
    [observable addObserver:self forKeyPath:@"arrangedObjects.name" options:0 context:nil];
  } else {
    [super bind:binding toObject:observable withKeyPath:keyPath options:options];
  }
}

Вот и все! Теперь, если какой-либо объект в schemeObjects изменит свое имя , я получу уведомление.

9
ответ дан 5 December 2019 в 14:06
поделиться

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

РЕДАКТИРОВАТЬ:

Кроме того, ваши объекты в массиве могут также отвечать на метод класса, называемый + keyPathsForValuesAffecting , где - ваше ключевое имя. Вот' s пример: paymentDue - это ключ, на который влияет изменение значений invoiceItems.count или paymentsMade . Когда invoiceItems.count или paymentsMade изменяется, все, что связано с paymentDue , отправляется уведомление.

+ (NSSet *) keyPathsForValuesAffectingPaymentDue:
{
    return [NSSet setWithObjects:@"invoiceItems.count", @"paymentMade", nil];
}

Если вы используете версию 10.4 или ориентируетесь на 10.4 или ранее вам нужно будет использовать вместо этого этот метод, но, по сути, он сводится к одному и тому же.

РЕДАКТИРОВАТЬ 2:

Чтобы прояснить другой ваш комментарий; вы все еще можете вручную вызвать каждый объект в массиве

[[NSNotificationCenter defaultCenter] postNotificationName:@"ModelDidChange" object:self];

. Затем с помощью некоторого кода контроллера вы можете зарегистрироваться для получения обновлений уведомлений от ваших объектов. Если вы выберете уникальное имя уведомления, вам не нужно будет вручную прослушивать определенные объекты, вы можете указать NSNotificationCenter , что хотите получать уведомления от любого объекта. Ваш контроллер может довольно легко определить, какой объект был изменен.

  1. Зарегистрируйтесь в центре уведомлений (эти методы должны быть в объекте контроллера):

     // Эта строка действительно может быть чем угодно, но сделайте это бросается в глаза.
    статический NSString * const ModelDidChangeName = @ "ModelDidChange";
    
    - (void) awakeFromNib
    {
     // использование nil в качестве параметра объекта сделает центр уведомлений
     // вызываем modelDidChange: независимо от отправителя.
     [[NSNotificationCenter defaultCenter] addObserver: селектор: @selector (modelDidChange :) имя: объект ModelDidChangeName: nil];
    }
    
  2. Реализовать метод обработки уведомления.

     - (void) modelDidChange: (NSNotification *) notification
    {
     MyModelClass * myObject = [объект уведомления];
     // при необходимости делаем что-нибудь с вашей моделью.
     // делаем что-нибудь и с вашим представлением
    }
    
  3. Заставьте объекты модели публиковать уведомления при изменении их частей:

     @implementation MyModelClass
    
    - (void) setSomething: (NSString *) newThing
    {
     [что-то автоматически выпускаемое];
     something = [новая копия];
     если (что-то == ноль)
     {
     // особый сценарий, когда что-то равно нулю
     // делаем что-то, изменяем атрибуты экземпляра MyModelClass
     [[NSNotificationCenter defaultCenter] postNotificationName: объект ModelDidChange: сам];
     // автоматически вызывается метод контроллера modelDidChange:.
     }
    }
    @конец
    

Но

Если ваша модель должным образом совместима с KVC и сделана с соответствующими обратными вызовами KVO, уведомления вручную не требуются.

3
ответ дан 5 December 2019 в 14:06
поделиться