Премахване на наблюдател на NSNotificationCenter в iOS 5 ARC

Имам проект, базиран на iOS 5 ARC, и имам затруднения относно това къде трябва да премахна наблюдателя за NSNotificationCenter наблюденията, които съм регистрирал в UIViewController. Подобни публикации в SO казват, че това трябва да се направи в метода -dealloc. Въпреки че този метод не се изисква в ARC проекти, аз го добавих със следния код:

- (void)dealloc {

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

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

Всяка помощ ще бъде оценена!


person Skoota    schedule 04.12.2011    source източник
comment
Имах същия проблем - вбесяващ. След часове отстраняване на грешки, чиста + компилация „поправи“ проблема. През цялото време преминавах през dealloc и се обаждах на -removeObsever както на iPhone, така и на симулатора. Така че, ако някой друг види този рядък проблем, първо изградете отново.   -  person emp    schedule 10.01.2012
comment
Как се регистрирахте на първо място? Трябва да покажете повече код.   -  person matt    schedule 16.02.2012
comment
NSNotification center запазва ли наблюдателя?   -  person Nick Weaver    schedule 13.03.2012
comment
Всъщност dealloc никога няма да бъде извикан при използване на ARC. Това е както е проектирано.   -  person Johan Karlsson    schedule 31.10.2014


Отговори (3)


Съвсем ясно е, че вашият dealloc метод не се извиква (нито пък removeObserver извикването).

Защо не премахнете наблюдателя на вашия UIViewController в методите viewDidUnload: или viewWillDisappear:?

person Michael Dautermann    schedule 04.12.2011
comment
viewDidUnload: се извиква само при условия на ниска памет, доколкото знам. Също така имам нужда обратните извиквания за известия да продължават да се задействат, ако изгледът е извън екрана, така че това означава, че не мога да използвам viewWillAppear: и viewWillDisappear: - person Skoota; 04.12.2011
comment

Силно препоръчвам да избягвате window.open, тъй като много браузъри и плъгини ще ги спрат. Това, от което се нуждаете, са диалогови прозорци. Вижте следните връзки за пример за потребителския интерфейс на jQuery.

http://jqueryui.com/demos/dialog/

Можете да намерите много други решения онлайн, които работят без или с други библиотеки.

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

- person Michael Dautermann; 04.12.2011

Ако вашият dealloc не се извиква, вероятно е защото някой все още държи препратка към контролера на изгледа. Може би трябва да маркирате нещо като __weak? Можете да използвате инструмента за разпределение, за да проследите какво се държи на вашия контролер за изглед.

person Jesse Rusak    schedule 04.12.2011

„Също така имам нужда обратните извиквания за известия да продължават да се задействат, ако изгледът е извън екрана“ -> може да се наложи да регистрирате UIApplicationWillEnterForegroundNotification. Ако е така, опитайте това:

- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"viewWillAppear");
    [super viewWillAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidEnterBackground:)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
}

- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"viewWillDisappear");
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    NSLog(@"applicationWillEnterForeground");
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidEnterBackground:)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
    // do your stuff here
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"applicationDidEnterBackground");
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationWillEnterForeground:)
                                                 name:UIApplicationWillEnterForegroundNotification
                                               object:nil];
}

Идеята е да добавяте или премахвате UIApplicationDidEnterBackgroundNotification при всяко влизане и излизане от вашия екран. Ние просто регистрираме UIApplicationWillEnterForegroundNotification, когато приложението влезе във фонов режим и го премахваме, след като се върне. Обърнете внимание, че ние просто премахваме UIApplicationDidEnterBackgroundNotification, когато viewWillDisappear.

Моят dealloc() не се извиква по някакъв начин, така че намерих този начин, надявам се да е полезен и за вас.

Наслади се :)

person thanhbinh84    schedule 12.09.2012
comment
забравихте да се обадите [супер ...] в тези. По документация. - person GregJaskiewicz; 21.11.2012
comment
Задължителни ли са? Не виждам никакъв проблем без тях, тъй като използвам този код в приложението си. - person thanhbinh84; 22.11.2012
comment
Ще видите проблем, когато суперобектът изпълнява свои собствени действия. Създайте си навика да го правите, защото така казва докторът. В противен случай един ден може да изпаднете в странни проблеми. - person GregJaskiewicz; 23.11.2012
comment
Благодаря Грег, прав си. Те споменават в api документа developer.apple .com/library/ios/#documentation/uikit/reference/ - person thanhbinh84; 23.11.2012
comment
@doraemon Да, рано или късно ще се натъкнете на проблеми, ако не извикате super в тези методи. Те всъщност правят някакви магически неща. Виждал съм няколко проблема, които са решени чрез добавяне на повиквания към super. - person Johan Karlsson; 31.10.2014
comment
Вместо да добавяте и премахвате тези известия, защо просто не ги добавите в init или viewDidLoad и премахнете всички наблюдатели в dealloc? Или ако наистина трябва да ги премахнете, когато изгледът изчезне, добавете ги и двете в viewWillAppear и ги премахнете в viewDidDisappear. Няма нужда от жонглиране :) - person Chris Nolet; 22.11.2014