我正在寻找一些已经失控的代码。通常情况下,我需要与一些远程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交织,你可以根据需要运行阻塞调用。
我想知道是否有人提出了更清洁的方法。我觉得这是大多数应用程序迟早要处理的事情,我不需要重新发明轮子。