removeObserver无法正常工作

use*_*271 5 objective-c nsnotificationcenter ios

我有下一个代码:

@implementation SplashViewVC

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.splashView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Default.png"]];
    self.activityIndicator.originY = 355.f;
    [[NSNotificationCenter defaultCenter] addObserverForName:NCDownloadComplete object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *n){
        NSInteger errorCode = [n.userInfo[@"errorCode"] integerValue];        
        [self.activityIndicator stopAnimating];
        if (errorCode == ERROR_CODE_NO_CONNECTION) {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Some problem with server" delegate:self cancelButtonTitle:@"try again" otherButtonTitles:nil];
            [alertView show];
        } else if (errorCode == 0) {
            [self dismissViewControllerAnimated:YES completion:nil];
        }
    }];
    [self downloadData];
}

- (void)downloadData
{
    [self.activityIndicator startAnimating];
    [[Server sharedServer] getMovieData];
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    [self downloadData];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super viewDidDisappear:animated];
}

@end
Run Code Online (Sandbox Code Playgroud)

所以我把断点放在viewDidLoad方法的开头,在viewDidDisappear.当我启动首先去的应用程序,viewDidload下载之后就去了viewDidDisappear.

但在我的应用程序中,我再次下载数据和发布notification: NSDownloadComplete.在这个VC中它是有效的,但我后来删除了:

[[NSNotificationCenter defaultCenter] removeObserver:self]
Run Code Online (Sandbox Code Playgroud)

这个VC viewDidLoad在开始时使用一次并且不能再次添加Observer.

怎么了?

编辑 我尝试将addObserver方法放入viewWillAppearviewWillDisappear- 没有结果.我NSLog(@"addObserver");之前添加

 [[NSNotificationCenter defaultCenter] addObserverForName...
Run Code Online (Sandbox Code Playgroud)

在viewDidLoad中

和写

- (void)viewDidDisappear:(BOOL)animated
{
    NSLog(@"removeObserver");
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super viewDidDisappear:animated];
}
Run Code Online (Sandbox Code Playgroud)

在日志中我看到:

2013-06-10 14:32:05.646 myApp[9390:c07] addObserver
2013-06-10 14:32:06.780 myApp[9390:c07] removeObserver
Run Code Online (Sandbox Code Playgroud)

怎么了?

编辑2 你可以看到必须删除观察者,但它再次在addObserver方法中运行块

在此输入图像描述

Mar*_*n R 24

除了添加/删除观察者呼叫没有正确平衡之外,还有其他答案中提到的另一个问题.

您删除观察者的代码是错误的.对于基于块的观测器,该返回值addObserver必须被给定为参数removeObserver.所以你应该添加一个属性

@property(nonatomic, strong) id observer;
Run Code Online (Sandbox Code Playgroud)

上课.然后你添加观察者

self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:NCDownloadComplete object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *n){
    // ...
}];
Run Code Online (Sandbox Code Playgroud)

并删除它

[[NSNotificationCenter defaultCenter] removeObserver:self.observer];
Run Code Online (Sandbox Code Playgroud)


Gui*_*gis 5

e1985试图暴露的是你的addObserverremoveObserver电话没有得到适当的平衡.viewDidLoadVC初始化后仅调用一次,但viewDidDisappear每次将视图控制器移出屏幕时调用.

要解决您的问题,您必须平衡您的电话addObserverremoveObserver通话,方法是将它们放入viewDidLoad其中dealloc,或者 - 如同e1985建议的那样 - viewDidAppear:viewDidDisappear:.

编辑:好了,你的问题来自于事实,你正在使用addObserverForName:object:queue:usingBlock:不注册self为观察者(如addObserver:selector:name:object:如果你传递会做self的第一个参数).

所以在你的情况下,[[NSNotificationCenter defaultCenter] removeObserver:self];什么都不做因为self不是观察者.您应该调用removeObserver:返回值addObserverForName:object:queue:usingBlock:,如文档中所示:

回报价值

一个不透明的对象充当观察者.

所以你的代码看起来应该是这样的:

// header file .h
@interface SplashViewVC : UIViewController

@property (strong, nonatomic) id downloadCompleteObserver;

@end

// implementation file .m
@implementation SplashViewVC

- (void)viewDidLoad
{
    [super viewDidLoad];

    // [...] snip

    self.downloadCompleteObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NCDownloadComplete object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *n){
        NSInteger errorCode = [n.userInfo[@"errorCode"] integerValue];        
        [self.activityIndicator stopAnimating];
        if (errorCode == ERROR_CODE_NO_CONNECTION) {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Some problem with server" delegate:self cancelButtonTitle:@"try again" otherButtonTitles:nil];
            [alertView show];
        } else if (errorCode == 0) {
            [self dismissViewControllerAnimated:YES completion:nil];
        }
    }];
    [self downloadData];
}

// [...] snip

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

@end
Run Code Online (Sandbox Code Playgroud)