способы связывания модельных классов в Objective-C - PullRequest
2 голосов
/ 29 сентября 2011

(надеюсь, кто-то исправит мою терминологию, если я ошибаюсь - я все еще перебираю термины)

У меня есть серия занятий в моей модели. Мне нужно получить некоторые данные из URL-адреса (SatDataGetter) и объединить их с определением местоположения и даты (DayCalculater), выполнить некоторые дополнительные вычисления (DataMixer), некоторую интерпретацию, чтобы сделать их понятными для пользователя (Advisor), а затем представить результаты в представлении.

Существуют проблемы с настройкой зависимостей и проверкой того, что, например, SatDataGetter имеет действительные данные до того, как будет вызван DataMixer, за до он будет вызван .. Вы поняли идею. Конечно, если местоположение меняется, мне нужно обновить все это снизу вверх. Как минимум я должен получить сообщение для ViewController и советника, чтобы перезагрузить их данные.

Проведенное мною исследование показывает, что NSNotification - это один из способов, но я также мог бы попробовать Наблюдение ключевых значений. Я нашел несколько старых постов (2009) по KVO, предлагая некоторые возможные проблемы и трудности с отладкой. http://www.mikeash.com/pyblog/key-value-observing-done-right.html

Какой метод предпочтительнее? Какие вопросы я должен учитывать при решении - Например: SatDataGetter по существу возвращает одно число. KVO кажется разумным способом для DataMixer отслеживать, что это значение, но я не думаю, что я хочу, чтобы все родительские классы выполняли KVO для зависимых переменных.

Когда вы выбираете NSNotification и когда KVO?

Ответы [ 4 ]

3 голосов
/ 19 октября 2011

Разница между NSNotifications и наблюдением значения ключа в значительной степени связана с сопряжением, но есть и последствия для производительности.

Каждый может подписаться на ваши NSNotifications. Все, что им нужно знать, это строка / ключ, под которым вы уведомляете. Им не нужно ничего знать о ваших классах / объектном графе и т. Д. Поэтому, когда вы хотите уведомить мир, который не знает о деталях вашего класса, NSNotification - это путь. Например, если вы отправляете фреймворк другим разработчикам, вероятно, лучше уведомить об этом с помощью NSNotification, чем раскрывать внутреннюю часть вашей фреймворка в той степени, которая может потребоваться для того, чтобы потребители могли получить ключ-значение. Наблюдайте за вашими объектами.

Чтобы KVO наблюдал за объектом, вы сначала должны иметь возможность получить ссылку на него, что не совсем верно для NSNotifications (но, как правило, бывает так, по моему опыту.) Во-вторых, вам нужно знать достаточно о реализация, чтобы знать, что наблюдать. С NSNotification уведомителю нужно только опубликовать строку / ключ уведомления. С KVO вам нужно знать имя свойства объекта. Конечно, кто-то может опубликовать статические строки и сказать вам «вы можете KVO me для этих свойств», но это фактически становится контрактом API, который может быть сложнее поддерживать в будущем. (Скажем, например, что вы хотите удалить это свойство в будущей версии - тогда вам нужно настроить другие вещи, чтобы продолжать отправлять эти уведомления и предоставлять значения, когда люди вызывают valueForKey: - короче, как только вы это сделаете, Вы никогда не сможете изменить это свойство.)

Другая вещь, которую следует помнить с этими различными степенями связи, заключается в том, что с KVO может ожидаться, что наблюдатель знает о деталях ваших классов / объектов. В конце концов, они регистрируют очень специфический интерес к вашему объекту; они утверждают, что знают, что это значит - как это работает. Поэтому вы можете ожидать, что они будут чувствительны к последствиям производительности. С помощью NSNotifications потребитель может наблюдать за вашим уведомлением, практически ничего не зная о вас, и может не знать о влиянии на производительность своих действий в ответ на уведомление.

Недостаток, разделяемый двумя подходами, заключается в том, что при отсутствии дополнительной работы они выполняются синхронно. Уведомляющий объект зависит от того, что наблюдатель решает сделать (синхронно), когда он получает уведомление. Эти два механизма отличаются тем, что для NSNotification довольно легко для уведомляющего объекта использовать executeSelector: afterDelay: заставить отправлять уведомление «асинхронно» (относительно вызова, который порождает уведомление) на следующем проходе запуска цикл (см. также NSNotificationQueue). Это не так легко возможно с КВО. Это различие само по себе может иметь решающее значение в определенной ситуации.

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

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

Основное различие между этими двумя и шаблоном делегата является то, что делегат отношение, как правило, 1: (. Один делегатом) 1 (Конечно, вы могли бы иметь массив делегатов, но это довольно редко, и спорный анти-паттерн. ) NSNotification и KVO оба по своей сути 1: N (много наблюдателей.)

В заключение я всегда хотел сказать: «Используйте самый высокий уровень абстракции, который сделает работу».Если вам нужны только отношения 1: 1, используйте делегата.Для уведомлений 1: N, если NSNotification будет работать - другими словами, если желаемое связывание низкое и / или уведомления являются крупнозернистыми или нечастыми, используйте NSNotifications.Если муфта затянута или необходимость мелкозернистая, используйте КВО.Также помните, что вы можете адаптировать шаблон делегата от 1: 1 до 1: N, отправив делегату NSNotifiations.С NSNotifications и KVO вы не можете реально контролировать, кто наблюдает за вами или сколько у вас наблюдателей.

0 голосов
/ 19 октября 2011

Как насчет NSOperations?

// create two ops, and set a dependency
DownloadOp *op = [[Download alloc] initWithURL:@"http://xxx"];
CalculationOp *op = [CalculationOp new];
[calculationOp addDependency:downloadOp];
// ... more steps

// add to the queue
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:downloadOp];
[queue addOperation:calculationOp];

// runloop for unit testing
while(!parserOp.isFinished) {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}

Внутри -[CalcuationOp start]:

    // get the result from the previous step
    id obj = [self.dependencies objectAtIndex:0];
    if ([obj isKindOfClass:[DownloadOp class]]){
        DownloadOp *op = (DownloadOp*) obj;
        self.input = op.output;
    }

Внутри AdvisorOp:

  // update the GUI from the main thread
  dispatch_queue_t mainQueue = dispatch_get_main_queue();
  dispatch_async(mainQueue,^{
    // update some UI element
 });

Затем прослушайте обновления местоположения наделегат CLLocationManager, чтобы начать все это.Я использую это с логикой, отделенной от операций, чтобы я мог модульно протестировать каждую часть в отдельности.
Преимущество: она выполняется асинхронно, и вы можете отменить операции в очереди в любое время.Недостаток: вы должны изучить NSOperation.

0 голосов
/ 19 октября 2011

Вам, вероятно, не нужна ни одна из этих стратегий, возможно, вы можете обойтись с какой-то иерархией делегатов.Если вы используете базовое местоположение или любую другую службу, из которой вы не можете получить надежные данные синхронно, то вы можете использовать ее в качестве отправной точки ... если у вас есть 2 такие службы (например, получение данных http и базовое расположение)), Тогда вам, возможно, придется выполнить некоторое кэширование и делегирование ... т. Е. Последнее лучшее местоположение + текущие http-данные передаются в представление.

0 голосов
/ 29 сентября 2011

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

Я склонен использовать NSNotifications для информирования других объектов о том, что что-то произошло. В вашем примере у меня может быть синглтон для обработки данных о местоположении, а затем отправка уведомления при изменении userLocation.

И, конечно, вы также можете использовать шаблон делегата для уведомления другого объекта об изменении.

Это не жесткие и быстрые правила, хотя ... Я не могу меняться по прихоти!

...