Grand Central Dispatch、viewWillAppear、viewDidAppear执行顺序混乱
我在我的标签栏应用程序中使用 GCD 进行后台下载。
第一步是在-viewWillAppear:
中进行一些后台下载(在加载视图之前设置一些基本数据)。
第二步是在-viewDidAppear:
中下载后台的其余部分
由于某种原因,-viewDidAppear:
中的调度块被调用 >在-viewWillAppear:
中的调度块之前。
这种情况仅在第一次加载应用程序并使用 GCD 后台方法切换到选项卡后发生一次。切换到另一个选项卡,然后使用 GCD 后台方法切换回该选项卡。第三次(以及所有其余的后续时间)我切换回它按预期工作(-viewWillAppear:
首先触发,然后-viewDidAppear:
)。
以下是我的代码摘录(-viewWillAppear:
和 -viewDidAppear:
):
-viewWillAppear:
- (void)viewWillAppear:(BOOL)animated {
DLog(@"viewWillAppear method running");
[super viewWillAppear:animated];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self setDiskCareerIds:[CareersParser idsFrom:@"disk"]];
[self setDownloadedCareerIds:[CareersParser idsFrom:@"web"]];
DLog(@"diskCareerIds after being set in viewWillAppear: %@", [self diskCareerIds])
DLog(@"downloadedCareerIds after being set in viewWillAppear: %@", [self downloadedCareerIds])
if ([[self downloadedCareerIds] isEqualToArray:[self diskCareerIds]]) {
DLog(@"viewWillAppear: ids equal, loading careers from disk.");
self.careers = [CareersParser loadCareersFromDisk];
dispatch_async(dispatch_get_main_queue(), ^{
[self.table reloadData];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
});
}
});
//[self downloadData];
}
-viewDidAppear:
- (void)viewDidAppear:(BOOL)animated {
DLog(@"viewDidAppear method running");
[super viewDidAppear:animated];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
if (![[self downloadedCareerIds] isEqualToArray:[self diskCareerIds]]) {
DLog(@"ids not equal, saving careers to disk.");
dispatch_async(dispatch_get_main_queue(), ^{
[self showLoadingView];
});
[CareersParser saveCareersToDisk];
self.careers = [CareersParser loadCareersFromDisk];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.table reloadData];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self removeLoadingView];
});
});
//[self download3];
//[self downloadData];
}
检查调试日志:Pastie。
I'm using GCD for background downloading in my Tab Bar app.
First step is to do some background downloading in -viewWillAppear:
(to setup some basic data before the view is loaded).
Second step is to the rest of the background downloading in -viewDidAppear:
For some reason, the dispatch block in -viewDidAppear:
gets called before the dispatch block in -viewWillAppear:
.
This only happens once after loading the application for the first time switching to the tab with the GCD background methods. Switching to another tab and then switching back to the tab with the GCD background methods. The third (and all the rest subsequent times) time I'm switching back it's works as expected (-viewWillAppear:
firing first and then -viewDidAppear:
).
Here are excerpts of my code (-viewWillAppear:
and -viewDidAppear:
):
-viewWillAppear:
- (void)viewWillAppear:(BOOL)animated {
DLog(@"viewWillAppear method running");
[super viewWillAppear:animated];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self setDiskCareerIds:[CareersParser idsFrom:@"disk"]];
[self setDownloadedCareerIds:[CareersParser idsFrom:@"web"]];
DLog(@"diskCareerIds after being set in viewWillAppear: %@", [self diskCareerIds])
DLog(@"downloadedCareerIds after being set in viewWillAppear: %@", [self downloadedCareerIds])
if ([[self downloadedCareerIds] isEqualToArray:[self diskCareerIds]]) {
DLog(@"viewWillAppear: ids equal, loading careers from disk.");
self.careers = [CareersParser loadCareersFromDisk];
dispatch_async(dispatch_get_main_queue(), ^{
[self.table reloadData];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
});
}
});
//[self downloadData];
}
-viewDidAppear:
- (void)viewDidAppear:(BOOL)animated {
DLog(@"viewDidAppear method running");
[super viewDidAppear:animated];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
if (![[self downloadedCareerIds] isEqualToArray:[self diskCareerIds]]) {
DLog(@"ids not equal, saving careers to disk.");
dispatch_async(dispatch_get_main_queue(), ^{
[self showLoadingView];
});
[CareersParser saveCareersToDisk];
self.careers = [CareersParser loadCareersFromDisk];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.table reloadData];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self removeLoadingView];
});
});
//[self download3];
//[self downloadData];
}
Check the debug log at Pastie.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,您在第一个块(在 viewWillAppear 中安排的那个块)中打印该日志消息在它完成了一堆解析之后,而不是在它实际开始执行时。
问题是全局队列是一个并发队列。因此,即使您首先调度第一个块,它有时落后于与其同时执行的另一个块也不足为奇。
一个简单的答案是创建一个串行队列,然后您将确保第一个块在执行第二个块之前完成。这似乎就是你想要的,对吧?
Well, you're printing that log message in that first block (the one scheduled in viewWillAppear:) after it has done a bunch of parsing, not when it actually starts executing.
The thing is that global queue is a concurrent queue. So even though you are scheduling that first block first, it's not surprising that it sometimes falls behind the other block which is executing concurrently with it.
One simple answer would be to create a serial queue, and then you'll be sure the first block completes before the second one is executed. That seems to be what you want, right?