与从非主线程调用UIKit方法相关的问题

时间:2016-02-06 20:13:15

标签: ios multithreading web-services grand-central-dispatch kvnprogress

我以这种方式实现了登录方法:

      [KVNProgress show];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //some error handling like:
                if ([_usernameField.text length] < 4) {
                    [KVNProgress showErrorWithStatus:@"Username too short!"];
                    _passwordField.text = @"";
                    return;
                }
       //Then I call login web service synchronously here:
       result = [ServerRequests login];
       dispatch_async(dispatch_get_main_queue(), ^{
       if(!result)
                    {
                        [KVNProgress showErrorWithStatus:@"problem!" completion:NULL];
                        _passwordField.text = @"";
                    }
                    else if([result.successful boolValue])
                    {
                        [KVNProgress showSuccessWithStatus:result.message];

                    }

});
});

它主要崩溃,并且只有主要队列(没有优先级默认值)的周围区块崩溃了!但问题是:KVNProgress只在错误处理区域显示而不是我们称之为Web服务的下一部分。它根本不是用户友好的!欢迎任何想法:)

1 个答案:

答案 0 :(得分:1)

根据the UIKit documentation 必须从主线程中调用以任何方式更新用户界面的方法:

  

在大多数情况下,仅使用应用程序主线程中的UIKit类 。对于从UIResponder 派生的类或涉及以任何方式操纵应用程序的用户界面的类,尤其如此。

我建议您尝试限制对主线程进行回调的次数,因此您希望尽可能多地批量处理用户界面更新。

然后,正如您所说的那样,只要您需要在后台处理中更新UI,就可以使用dispatch_async回调主线程。

因为它是异步的,它不会中断你的后台处理,并且应该对主线程本身造成最小的中断,因为大多数UIKit组件的更新值相当便宜,它们&# 39;只需更新它们的值并触发它们setNeedsDisplay,以便它们在下一个运行循环中重新绘制。

从您的代码中,您的问题似乎是您从后台线程调用此问题:

if ([_usernameField.text length] < 4) {
    [KVNProgress showErrorWithStatus:@"Username too short!"];
    _passwordField.text = @"";
    return;
}

这是100%的UI更新代码,因此应该在主线程上进行。

虽然,我不知道KVNProgress的线程安全性,但我认为它也应该在主线程上调用,因为它向用户提出错误。

因此,您的代码应该像这样 (假设它首先在主线程上发生):

[KVNProgress show];

//some error handling like:
if ([_usernameField.text length] < 4) {
    [KVNProgress showErrorWithStatus:@"Username too short!"];
    _passwordField.text = @"";
    return;
}

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    //Then I call login web service synchronously here:
    result = [ServerRequests login];

    dispatch_async(dispatch_get_main_queue(), ^{
        if(!result) {
            [KVNProgress showErrorWithStatus:@"problem!" completion:NULL];
            _passwordField.text = @"";
        } else if([result.successful boolValue]) {
            [KVNProgress showSuccessWithStatus:result.message];
        }
    });
});