1

-- 编辑,见下面的更新解决方案 --

我在这里有一个应用程序,可以在其中在后台线程中下载一些数据。

每次下载 5 个项目时,在我的主视图控制器中,我都会发布一条通知,指出已下载 5 个项目。

在我的其他 4 个视图控制器之一中,它们本身是导航堆栈上的根视图控制器,我深入了解了详细信息页面。(典型的5个标签栏界面)

这个详细信息页面是另一个视图控制器,我在其中对 viewDidLoad 方法做了一个 NSNotificationCenter defaultCenter addObserver。

这里的问题是,当通知发布时,我的详细信息页面的根视图控制器会收到通知,但详细信息页面本身没有收到通知。

虽然我的数据是在后台线程中下载的,但我正在调用 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() 方法永远不会被执行。

我删除了 object 参数,现在它可以工作了。

新的 viewDidLoad() 应该是这样的:

-(void)viewDidLoad
{
    ...
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomething:) name:@"notif_batchDownloaded" object:nil];
    ...
}

我原本以为我可以像某种标记一样使用“对象”参数来帮助我的回调方法识别在我将多个通知发送到同一个回调方法的情况下发送了哪个通知。

快速阅读 Apple 文档会发现 object 参数用于识别观察者从哪个对象观察通知。即多个对象可以发送相同的通知,该对象参数字段标识它希望仅从哪个对象接收通知。

例如

视图控制器 A 和视图控制器 B 都 postNotificationName:@"notif_foo"。

视图控制器 C 将自己添加为通知“notif_foo”的观察者,但它可以通过将视图控制器 A 指定为对象参数来选择仅从视图控制器 A 接收“notif_foo”。

愚蠢的我没有意识到在我的通知回调方法中我可以去:

if([notification name] isEqualToString:@"notifName"])
{
   ...
}
else
{
   ...
}

希望这可以帮助其他任何在这个问题上拉扯头发的人。

4

1 回答 1

0

您可以在 appdelegate 中设置标志,以告知选择了哪个控制器。然后发布该控制器的通知。注意这里你需要在你想要发布通知的所有类中实现你的代码,特别是如果有 ui 更改或类被释放

于 2012-05-02T13:28:49.953 回答