GCD中长时间运行操作的优雅模式,并向用户报告错误?

时间:2013-01-08 08:13:50

标签: ios cocoa-touch design-patterns error-handling cocoa-design-patterns

我正在寻找一些已经失控的代码。通常情况下,我需要与一些远程API(例如Parse和Facebook,可能是Core Data)进行交互,而用户正在等待,盯着我的活动指示器旋转。

我的要求是:

  • 一切都很慢,当然,必须在后台线程中
  • 没有静默或忽略的错误消息。
  • 我想帮助用户(以便他不会惊慌失措)和我自己(当我得到支持电话时,我需要弄清楚出了什么问题)并尽可能提供有用的错误消息。
  • 我希望逻辑可以维护。像下面那样的块很快就会出现圈复杂性,如果处理得不好就会成为一个噩梦,特别是添加了多线程。

我现在使用的模式如下:

- (void)sampleFacebookProcessingCall
{
    [self.spinner startAnimating];
    [FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *facebookRequestError)
    {
        // we're back in main queue, let's return to a secondary queue
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

            // don't want do display the actual error to the user
            NSString *errorMessage;
            NSError *error;
            @try {
                if (facebookRequestError) {
                    errorMessage = @"Could not connect to Facebook, please try again later.";
                    return;
                }

                [Helper someParseCall:&error];
                if (error) {
                    errorMessage = @"The operation could not be completed, please try again later. Code: FOO1";
                    return;
                }

                [Helper someOtherParseCall:&error];
                if (error) {
                    errorMessage = @"The operation could not be completed, please try again later. Code: FOO2";
                    return;
                }

                [...]
            }
            @finally {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.activityIndicator stopAnimating];
                    if (errorMessage) {
                        // there might be half-baked state out there afer the error
                        [self cleanupResources];
                        [UIHelper displayErrorAlertViewWithMessage:errorMessage];
                    }
                });
            }
         });
     }];
 }

现在,当发生错误时,肯定会有不同的模式通过流进行转义。带有返回的@ try / @ finally模式(与清除标签的旧学校goto相同)是一种方式。另一种方法是使用错误对象作为“应该继续”变量并执行以下操作:

if (!error) {
    doStuff(&error)
}
if (!error) {
[...]

添加GCD会使事情变得复杂,因为现在你必须确保繁重的工作总是在后台完成,并且只在主线程中报告错误。每个API的库的工作方式都有所不同,所以你有类似Facebook的东西,它只接受在主线程中执行的块,你必须与Parse交织,你可以根据需要运行阻塞调用。

我想知道是否有人提出了更清洁的方法。我觉得这是大多数应用程序迟早要处理的事情,我不需要重新发明轮子。

0 个答案:

没有答案