我很紧张您从后台队列中接受了有关的答案,因为从实际角度来看,这与您的基于 - 的实现sendSynchronousRequest
没有什么不同。didReceiveData
具体来说,如果您确实从后台队列执行同步请求,它不会让“其他一切都等待”。但是,如果您忽略了从后台队列执行此同步请求(即,如果您从主线程执行此请求),您最终会得到一个可怕的用户体验(应用程序被冻结并且用户想知道应用程序是否已崩溃),并且更糟糕的是,如果花费太长时间,您的应用程序可能会被 iOS“看门狗进程”杀死。
完全尊重各种答案,在后台队列上发送同步请求与现有NSURLConnectionDataDelegate
的基于 - 的方法没有区别。您真正需要做的是接受应用程序的其余部分不会冻结这一事实,因此只需更新 UI 以让用户知道发生了什么,即 (a) 提供一些应用程序没有死机的视觉提示;(b) 阻止用户与您现有的 UI 进行交互。
例如,在发出网络请求之前,添加一个视图来覆盖/调暗 UI 的其余部分,防止用户与现有 UI 交互,并添加一个微调器,让用户知道应用程序正忙于做某事。因此,为 a 定义一个类属性,UIView
它将使 UI 的其余部分变暗:
@property (nonatomic, strong) UIView *dimView;
然后,在网络请求之前,更新 UI:
// add a view that dims the rest of the UI, so the user has some visual cue that they can't use the UI yet
// by covering the whole UI, you're effectively locking the user out of using the app
// until the network request is done
self.dimView = [[UIView alloc] initWithFrame:self.view.bounds];
self.dimView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
self.dimView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.dimView];
// add a spinner that shows the user that something is really happening
UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicatorView.center = self.dimView.center;
indicatorView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
[indicatorView startAnimating];
[self.dimView addSubview:indicatorView];
[self callWebService:URL withSOAP:SOAP];
然后,在connectionDidFinishLoading
方法中(或者如果您sendSynchronousRequest
从后台队列中使用,则在代码的后半部分中调度到该后台队列),在完成数据解析后,您希望:
[self.dimView removeFromSuperview];
self.dimView = nil;
// now do what ever to need do to update your UI, e.g.:
//
// [self.tableView reloadData]
但关键是您绝对不想从主队列发出同步网络请求。您应该 (a) 异步执行网络请求(在后台队列上同步或按照您最初实现的方式),以便 iOS 看门狗进程不会杀死您的应用程序;(b) 让用户知道应用程序正在发出一些网络请求并且没有冻结它们(例如 a UIActivityIndicatorView
;和 (c) 当请求完成时,删除这些“应用程序正在发出网络请求”的 UI 元素并刷新现在您的网络请求已完成,其余的 UI。
最后,在测试您的应用程序时,请确保您在真实的网络环境中对其进行测试。我建议您安装硬件 IO 工具(可在 Xcode 菜单中的“打开开发者工具”-“更多开发者工具”下找到)并查看网络链接调节器。这让您可以在 iOS 模拟器上模拟真实世界的网络情况(例如,糟糕的 3G 或 Edge 网络条件)。当我们在具有理想网络连接的典型开发环境中测试我们的应用程序时,我们会陷入一种错误的性能感。“在野外”的设备会遭受各种网络性能下降的情况,最好在类似的、次优的网络情况下测试您的应用程序。