有人可以在 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
希望对您有所帮助
简介:我有一个发送通知的队列。视图控制器订阅它们,当它接收到它们时,它会显示图像。
问题:第一次,一切顺利。当我稍后返回视图时,我看到收到通知但未显示图像的日志。
注意:后台线程是一个队列: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
希望对您有所帮助