1

我正在寻找清理一些我失去控制的代码。通常情况下,我需要与几个远程 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 交织在一起,如果你愿意,你可以运行阻塞调用。

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

4

0 回答 0