有人可以在 iOS(中央调度 + 通知 + UI 刷新)中解释这种奇怪的行为吗?

Can someone explain this strange behaviour in iOS (central dispatch + notifications + UI refresh)?

简介:我有一个发送通知的队列。视图控制器订阅它们,当它接收到它们时,它会显示图像。

问题:第一次,一切顺利。当我稍后返回视图时,我看到收到通知但未显示图像的日志。

注意:后台线程是一个队列:dispatch_queue_create("scan", DISPATCH_QUEUE_SCAN)并从该队列发布通知。

@property(strong, nonatomic) id observer;

- (void)viewDidAppear:(BOOL) animated {
  [super viewDidAppear:animated];
  self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:MY_NOTIF object:nil queue:nil usingBlock:^(NSNotification *note) {
    dispatch_async(dispatch_get_main_queue(), ^{
      NSLog(@"notification");
      [self.img setImage:[UIImage imageNamed:@"register-ok"]];
      [self.img setNeedsDisplay];  // useless
    });
  }
}

- (void)viewDidDisappear:(BOOL) animated {
  [super viewDidDisappear:animated];
  [[NSNotificationCenter defaultCenter] removeObserver:observer name:MY_NOTIF object:nil];
}

这真让我抓狂。预先感谢您的帮助

编辑:完成更改:

NSLog(@"viewDidAppear. createObserver. self: %@");
[[NSNotificationCenter defaultCenter] addObserverForName:MY_NOTIF object:nil queue:nil usingBlock:^(NSNotification *note) {
  NSLog(@"will call redraww. self: %@");
  [self performSelectorOnMainThread:@selector(redraww:) withObject:nil waitUntilDone:YES];
}

-(void) redraww:(NSObject*)input {
    NSLog(@"redraww self : %@", self);
    [self.img setImage:[UIImage imageNamed:@"register-ok"]];
}

-(void) onRegistrationFinish {
  NSLog(@"remove observer. self %@", self);
  [[NSNotificationCenter defaultCenter] removeObserver:self name:(NSString *)NOTIF_SOLE_UUID object:nil];
}

控制台日志

viewDidAppear. createObserver self: <RegisterLeftViewController: 0x15e34550>
will call redraww. self:<RegisterLeftViewController: 0x15e34550>
redrawww self : <RegisterLeftViewController: 0x15e34550>
remove observer. self <RegisterLeftViewController: 0x15e34550>

************************* Second time

viewDidAppear. createObserver self: <RegisterLeftViewController: 0x15e98ba0>
will call redraww. self:<RegisterLeftViewController: 0x15e34550>
redrawww self : <RegisterLeftViewController: 0x15e34550>
remove observer. self <RegisterLeftViewController: 0x15e98ba0>

看来您正在做一些可能会引起麻烦的事情。

问题可能来自多个地方。以下是一些可能会解决问题的方法:

  • 将观察者注册移动到 viewDidLoad
  • 将观察者注销移动到 dealloc
  • 使用 __block __weak id observer 确保在您的通知处理程序中正确捕获 self。参见 iOS NSNotificationCenter Observer not being removed

希望对您有所帮助