Кога да използвате NSNotificationCenter

Искам да имам множество наблюдатели на множество събития на един обект (отношение 1 към N).

Механизъм за постигане на тази задача е предоставен от NSNotificationCenter. Механизмът изглежда доста пресилен, когато се използва за моя проблем.

Как бих го направил ръчно без използването на NSNotificationCenter:

- (void)addDelegate:(id<DelegateProtocol>)delegate;
- (void)removeDelegate:(id<DelegateProtocol>)delegate;

за добавяне и премахване на наблюдатели от моя обект.

- (void)someEventFired:(NSObject<NSCopying> *)eventData
{
    for (id delegate in delegates) {
        NSObject *data = [eventData copy];
        [delegate someEventFired:data];
    }
}

Този механизъм е ясен и лесен за изпълнение, без обектите да споделят допълнителни низове.

  • Има ли официален модел за делегати 1 към N (като C# събития) в iOS рамка освен NSNotificationCenter?
  • Кога трябва да се използва NSNotificationCenter и кога не?
  • Кога трябва да се използва изпълнение като това, което предлагам тук и кога не?

person Etan    schedule 31.05.2012    source източник
comment
Рядко или изобщо използвах NSNotificationCenter, но използвах същия метод, който описвате. Използвал съм това в множество приложения за iOS (бих казал над 50 приложения) в продължение на много години, досега не съм виждал проблем с това. Възможна грешка може да бъде, че трябва да сте сигурни, че понякога премахвате наблюдатели, или те може да не бъдат освободени, когато се очаква, защото са задържани от пазителя на делегатите.   -  person Jonny    schedule 05.12.2014
comment
Мисля, че въпреки че NSNotificationCenter не е подходът, който познаваме от C#, все пак трябва да се съсредоточим върху използването на дизайнерските модели за конкретната платформа, за която работим. Въпреки това използвах NSNotificationCenter в няколко приложения сега (не толкова много, колкото вас обаче) и не мисля, че кодът се е влошил чрез него.   -  person Etan    schedule 05.12.2014


Отговори (7)


По конвенция делегатите вероятно трябва да се използват само за отношения 1:1. Ако наистина се нуждаете от връзки 1:N за този тип функционалност, имате две възможности:

  1. Както споменахте, NSNotificationCenter< /a>.
  2. Наблюдение на ключ-стойност (известно още като KVO).

KVO е подходящ, ако ви интересува само кога се променя определено свойство на обект. В противен случай наистина трябва просто да обмислите използването на NSNotificationCenter. Можете дори да бъдете уведомени само когато конкретен обект публикува това известие, като прехвърлите този обект в метода addObserver:selector:name:object:.

Apple използва NSNotification в подобни сценарии (като известията, дефинирани за UITextField, включително UITextFieldTextDidBeginEditingNotification, UITextFieldTextDidChangeNotification и UITextFieldTextDidEndEditingNotification).

person Sebastian Celis    schedule 31.05.2012
comment
Можете ли да ми кажете дали го използвам правилно? stackoverflow.com/questions/42111829/ - person Leandro De Mello Fagundes; 10.02.2017

използването на известия е излъчване: 1 подател просто изпраща информация и който някога се е включил, я получава. Малко като радиостанция, няма обратен канал (нека за момента забравим за телефоните)

делегирането е нещо различно. Обектът, който иска от делегат да направи нещо, обикновено се нуждае от резултат от тази заявка, следователно делегирането е комуникация 1 към 1, която винаги се инициира от обекта, а не от делегата (докато обектът може да има методи, които може да бъде извикан, за да информира обекта да инициира комуникацията, т.е. [tableView reloadData]).

Така че, ако подателят трябва да получи обратно данни, това е делегиране. Ако подателят не се интересува от нищо след излъчването, отидете с известия.

Ако попаднете в ситуацията, че имате нужда от делегиране, но няколко обекта трябва да изпълняват протокола. трябва да имате 1 делегат, който съдържа препратки към другите обекти и извиква методите от името на подателите — или можете да използвате блокове.

person vikingosegundo    schedule 31.05.2012
comment
Днес бих имал само един обект, който всички VC споделят и който ги информира. - person vikingosegundo; 13.05.2016

NSNotificationCenter не е излишен за това, което предлагате, това е точното решение. Това не позволява на наблюдавания обект да знае или да се грижи за своите наблюдатели, което прави вашия код по-свободно свързан и по-чист.

Споделянето на низове за имена на известия е тривиално и те могат да бъдат дефинирани или в споделен константен файл, или в заглавката на наблюдавания обект, ако вашите наблюдатели трябва да импортират тази заглавка, за да вършат работата си.

person jrturton    schedule 31.05.2012

Предложеното от вас решение не е нито по-просто от използването на NSNotificationCenter, нито е безопасно за нишки.

За да направите нишката на вашето решение безопасна, ще трябва да предоставите механизъм, който да предотврати промяната на масива на делегатите, докато се изпълнява цикълът за изпращане на събитие.

Вашето решение също така изисква да поддържате масива от делегати във вашия клас. С NotificationCenter можете просто да използвате центъра по подразбиране и не е необходимо да прилагате методите за добавяне/премахване във вашия клас. Вместо това екземплярите могат да се регистрират, за да получават известия, както сметнат за най-подходящо (селектор/блок, опашка, източник). Вашият изходен клас не трябва да се тревожи за тези подробности. Трябва само да се регистрира като източник на известия от определен тип. Използването на блокове за обработка на известия е наистина удобно.

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

В крайна сметка механизмът, който решите да използвате, зависи от това колко най-добре се прилага за вашия конкретен случай на употреба.

person Tom Pelaia    schedule 31.05.2012

Делегирана връзка 1 към N няма смисъл. Погледни

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row

например. Ами ако този обект наистина има n делегата? Как трябва да реши кой от n изгледа, който получава обратно от всички свои делегати, да се използва? Делегатите са точно този принцип 1 към 1.

NSNotificationCenter е правилният подход. Просто използвайте

addObserver:selector:name:object:

съответно

postNotification:

Това определено не е твърде много код. И е много лесно за вас, тъй като центърът обработва всички обаждания.

person pbx    schedule 31.05.2012

Не искате да използвате NSNotificationCenter за нищо друго освен събития за цялата система (напр. появата на клавиатурата или друго подобно събитие). Причината е, че той напълно не е безопасен за тип, може да направи всичко зависимо от всичко и че вече не получавате проверки по време на компилиране или резултати от търсене на използване.

Според мен KVO не трябва да се използва за наблюдение на промени извън обекта, който слушате, тъй като има подобни недостатъци (без проверки по време на компилиране, сривове, ако не премахнете слушателите правилно или не ги регистрирате два пъти).

Моделът addDelegate/removeDelegate, който поставяте, е напълно правилният път според мен, тъй като има предимството да поддържа проверки за безопасност на типа и компилатор и прави зависимостите изрични. Единственият проблем е, че Apple не предоставя готово решение за този модел, тъй като имате нужда от тип колекция, която слабо запазва своите елементи, за да избегнете цикли на запазване.

Вижте обаче кода от моята рамка на BMCommons, която решава този проблем спретнато с помощта на BMNullableArray и макроси. Вижте BMCore.h заглавка за дефиниция на тези макроси:

BM_LISTENER_METHOD_DECLARATION(protocol)
BM_LISTENER_METHOD_IMPLEMENTATION(protocol)

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

person Werner Altewischer    schedule 24.11.2017

Казвам, че NSNotificationCenter трябва ВИНАГИ да се използва над модела на делегат, освен в ситуации, в които отправяте запитване към делегат за информация (напр. -webView:shouldLoadRequest:). Той е по-стабилен, по-лесен за внедряване и води до по-чист код, отколкото при опит за използване на делегат. Другата алтернатива са блокове, които могат да бъдат добри, но могат да бъдат болка, когато става въпрос за управление на паметта.

В крайна сметка зависи от вас, но мисля, че NSNotificationCenter е най-добрият начин да отидете в почти всяка ситуация, дори и само за функционалността на множество наблюдатели.

person Richard J. Ross III    schedule 31.05.2012