返回主线程时,异步UIView内容未显示

时间:2013-12-12 19:04:44

标签: ios objective-c uiview uiviewcontroller

加载我的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]来检查是否所有内容都存在,即使我没有看到它们,它们也都是正确的框架。

任何指针? - layoutSubviews没有帮助! - 将背景颜色放在发票视图中显示背景颜色

3 个答案:

答案 0 :(得分:3)

我怀疑这一行是你的问题:

UIView *v_invoice_content = [[BRNetwork sharedNetwork] invoiceViewForBooking:locBooking.objectId];

当您在后台调度队列中调用它时。任何涉及UIKit的工作都应该在主队列/线程上完成。将其移动到主线程块中,或者如果构建视图依赖于来自网络调用的数据,请更改invoiceViewForBooking方法以首先返回数据,并使用该数据在主线程中构建视图。 / p>

   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

答案 1 :(得分:0)

解决!我最终删除了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的视图可以在不等待视图加载远程数据的情况下出现!

答案 2 :(得分:-1)

您应该将代码放在viewDidAppear而不是viewDidLoad。与显示相关的内容(甚至启动异步块)应始终位于viewWillAppearviewDidAppear

此外,我建议您使用dispatch_async(dispatch_get_main_queue(), ^{})而不是dispatch_sync,因为您仍希望块执行异步(但在主线程上)。

别忘了在viewDidAppear中调用超级方法。