【发布时间】:2012-05-11 23:30:57
【问题描述】:
-- 编辑,见下方更新解决方案--
我在这里有一个应用程序,可以在后台线程中下载一些数据。
每次下载 5 个项目时,在我的主视图控制器中,我都会发布一条通知,指出已下载 5 个项目。
在我的其他 4 个视图控制器之一中,它们本身是导航堆栈上的根视图控制器,我深入了解了一个详细信息页面。 (典型的5个标签栏界面)
这个详细信息页面是另一个视图控制器,我在其中对 viewDidLoad 方法做了一个 NSNotificationCenter defaultCenter addObserver。
这里的问题是,当通知发布时,我的详细信息页面的根视图控制器会收到通知,但详细信息页面本身没有收到通知。
虽然我的数据是在后台线程中下载的,但我正在使用 dispatch 方法调用 performSelectorOnMainThread:。在dispatch方法中调用[[NSNotificationCenter defaultCenter] postNotificationNamed:object:];
所以:
.... downloading batches of 5 items in a background thread ....
...
... downloaded calling [self performSelectorOnMainThread:@selector(foo) WithObject:nil WaitUntilDone:NO]; ...
...
// foo method
-(void)foo
{
// theoretically, this notification should be delivered and received in the main thread since this foo() method is told to execute on the main thread above
[[NSNotificationCenter defaultCenter] postNotificationName:@"notif_batchDownloaded" object:nil];
}
...
我在我的根视图控制器中收到通知,但不是我的详细信息页面。
1) 当下载过程开始时,我已经在查看详细信息页面,所以不,我认为详细信息页面视图控制器没有被释放
2) 详细信息页面视图控制器显然正在观察主线程上的通知,如上所述,通知被告知要发布在主线程上。
所以问题是,是否还有其他原因阻止子级视图控制器接收通知?
我认为我没有超出任何通知观察者限制。我什至注释掉了其他通知,但没有任何区别。
每次下载 5 个项目时都会发送通知,因此在发送通知之前我无法查看详细信息页面。即使我以某种方式错过了前 5 个,我至少应该收到第 2 个 5、第 3 个 5、第 4 个 5 等等。
可能是根视图控制器先收到通知,然后无法将通知传递给其子级视图控制器?
我没有想法。
更新 - 找到罪魁祸首!
我终于知道它坏在哪里了。多么美味的皮塔饼。
在我之前的 viewDidLoad 方法中,我是这样的:
-(void)viewDidLoad
{
...
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomething:) name:@"notif_batchDownloaded" object:@"notif_batchDownloaded"];
...
}
这里的问题是我传入的“object”参数。我使用通知的名称作为“object”字段的参数,但这不知何故导致我的 doSomething() 方法永远不会被执行。
我删除了对象参数,现在它可以工作了。
新的 viewDidLoad() 应该是这样的:
-(void)viewDidLoad
{
...
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomething:) name:@"notif_batchDownloaded" object:nil];
...
}
我原本以为我可以像某种标记一样使用“object”参数来帮助我的回调方法识别在我有多个通知发送到同一个回调方法的情况下发送了哪个通知。
快速阅读 Apple 文档会发现 object 参数用于识别观察者从哪个对象观察通知。 IE。多个对象可以发送相同的通知,该对象参数字段标识它希望仅从哪个对象接收通知。
例如
View Controller A 和 View Controller B 都 postNotificationName:@"notif_foo".
视图控制器 C 将自己添加为通知“notif_foo”的观察者,但它可以选择仅从视图控制器 A 接收“notif_foo”,方法是将视图控制器 A 指定为对象参数。
愚蠢的我没有意识到在我的通知回调方法中我可以去:
if([notification name] isEqualToString:@"notifName"])
{
...
}
else
{
...
}
希望这可以帮助其他正在解决这个问题的人。
【问题讨论】:
-
你确定 viewDidLoad 在细节内部被调用(并且它在 main 上)?如果不确定,请使用 NSLog。
-
这听起来很粗糙,让我改写一下 - 是的,我相信 viewDidLoad 是在主线程上执行的,因为我在详细信息页面上看到了所有界面元素。如果绘图是在后台线程上完成的,那么它将不可见,但我会在我的详细信息页面中看到我的按钮和标签,所以我确信它正在主线程上执行。
标签: iphone ios nsnotificationcenter