加载UIViewController时,我基本上在页面中间放置一个微调器,直到加载内容,然后返回主线程添加子视图:
- (void)viewDidLoad {
[super viewDidLoad];
UIActivityIndicatorView *aiv_loading = ... // etc
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Load content
NSString *s_checkout = [[BRNetwork sharedNetwork] getCheckoutInstructionsForLocation:self.locBooking.location];
UIView *v_invoice_content = [[BRNetwork sharedNetwork] invoiceViewForBooking:locBooking.objectId];
// Display the content
dispatch_sync(dispatch_get_main_queue(), ^{
if (s_checkout && v_invoice_content) {
[aiv_loading removeFromSuperview];
[self showContentWithText:s_checkout AndInvoice:v_invoice_content];
} else {
NSLog(@"No data received!"); // is thankfully not called
}
});
});
}
- (void) showContentWithText:(NSString *)s_checkout AndInvoice:(UIView *)v_invoice {
[self.view addSubview:[self checkoutTextWithText:s_checkout]]; // Most of the time displayed text
[self.view addSubview:[self completeCheckout]]; // always Displayed UIButton
[self.view addSubview:[self divider]]; // always displayed UIImageView
// Summary title
UILabel *l_summary = [[UILabel alloc] initWithFrame:CGRectMake(0, [self divider].frame.origin.y + 6 + 10, self.view.bounds.size.width, 20)];
l_summary.text = NSLocalizedString(@"Summary", nil);
[self.view addSubview:l_summary];
CGRect totalRect = CGRectMake([self divider].frame.origin.x, [self divider].frame.origin.y + 6 + 30, self.view.bounds.size.width - [self divider].frame.origin.x, 90);
_v_invoice = v_invoice;
_v_invoice.frame = totalRect;
[self.view addSubview:[self v_invoiceWithData:v_invoice]]; // THIS Pretty much never displayed
UITextView *l_invoice = [[UITextView alloc] initWithFrame:CGRectMake(0, _v_invoice.frame.origin.y + _v_invoice.frame.size.height + offset, 320.0, 50)];
l_invoice.text = NSLocalizedString(@"summary_emailed", nil);
[self.view addSubview:l_invoice]; // Always displayed
}
但是,并不是所有内容都显示出来。发票一开始从不在那里,但几分钟后就会显示出来。另一个异步创建的字符串s_content有时不会显示。
这似乎是随机的内容创建。最终结果是相当整洁的,但对于生产版本来说并不可靠。
我使用了未记录的[self.view recursiveDescription]来检查是否所有东西都在那里,即使我看不到,它们也都有似乎正确的框架。
有指针吗?-layout子视图没有帮助!-为发票视图添加背景色就是显示背景色
我怀疑这一行是您的问题:
UIView *v_invoice_content = [[BRNetwork sharedNetwork] invoiceViewForBooking:locBooking.objectId];
当您在后台调度队列中调用它时。任何涉及UIKit的工作都应该在主队列/线程上完成。将其移动到主线程块中,或者如果构建视图依赖于网络调用中的数据,请更改invoiceViewForBooking
方法以首先返回数据,然后使用该数据在主线程中构建视图。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Load content
NSString *s_checkout = [[BRNetwork sharedNetwork] getCheckoutInstructionsForLocation:self.locBooking.location];
id someData = [[BRNetwork sharedNetwork] invoiceDataForBooking:locBooking.objectId];
// Display the content
dispatch_async(dispatch_get_main_queue(), ^{
UIView *v_invoice_content = [invoiceViewWithData:someData];
});
});
我还建议在主队列中使用dispatch_async
而不是dispatch_sync
。
已解决!我最终删除了dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
只将异步块留在主队列上:
// Display the content from a new async block on the main queue.
dispatch_async(dispatch_get_main_queue(), ^{
[aiv_loading removeFromSuperview];
NSString *s_checkout = [[BRNetwork sharedNetwork] getCheckoutInstructionsForLocation:self.locBooking.location];
[self showContentWithText:s_checkout AndInvoice:[[BRNetwork sharedNetwork] invoiceViewForBooking:locBooking.objectId]];
});
它做到了,viewcontroller的视图可以在不等待视图加载远程数据的情况下出现!
您应该将代码放在viewDidAppear
而不是viewDidLoad
中。与显示相关的内容(甚至启动异步块)应该始终在viewWillAppear
或viewDidAppear
中。
此外,我建议您使用dispatch_async(dispatch_get_main_queue(), ^{})
而不是dispatch_sync
,因为您仍然希望您的块异步执行(但在主线程上)。
不要忘记在viewDidAppear
中调用超级方法。