进入后台时的 NSURLConnection 最佳实践
Posted
技术标签:
【中文标题】进入后台时的 NSURLConnection 最佳实践【英文标题】:NSURLConnection best practise when enter background 【发布时间】:2013-08-03 15:50:31 【问题描述】:我在我的应用程序中注意到,当应用程序在加载时进入后台时会导致错误,例如 "timeout" 或 "host name not found" 。
这是由于进程长时间不允许连接在后台运行。
但是这种错误信息会影响用户体验。那么我应该怎么做才能取消交易呢?我应该取消所有连接吗?我试图在这里搜索 SO 中的问答,但找不到答案。
有关更多信息,我的应用程序使用 NSURLConnectionDelegate 方法。我有一个存储单例来管理与我的服务器的所有连接。 NSURLConnection 也在自定义对象中被调用和管理。
我试图只是 [连接取消] 在 - applicationDidEnterBackground: 但这会使 UI 损坏,因为我加载数据以放入 UITableViewCell 等。谁能指出解决此类问题的示例?
更新代码:
- (void)applicationDidEnterBackground:(UIApplication *)application
__block UIBackgroundTaskIdentifier backgroundTask; backgroundTask =
[application beginBackgroundTaskWithExpirationHandler: ^
[application endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid; ];
我可以把这段代码放在 appDelegate 中吗?与将 beginBackgroundTaskWithExpirationHandler 放在我想在后台继续运行的任务之前和 endBackgroundTask 在该任务完成后放置相比,这样做的缺点是什么?我的代码有一个直接处理 NSURLConnection 的对象。
【问题讨论】:
你不是说[connection cancel]
吗?
是的,没错。就是[连接取消]没有停止。
【参考方案1】:
您可以在进入后台后继续运行NSURLConnection
一段时间。苹果没有公布确切的时间段,但它是 10 分钟。有关如何使用beginBackgroundTaskWithExpirationHandler:
请求更多时间来完成下载的详细信息,请参阅Executing a Finite-Length Task in the Background。
在大多数情况下,您不应主动取消下载。您应该等到系统使您过期,然后在那时处理错误。如果您的下载时间很短,则没有理由取消它(在大多数情况下,连接最昂贵的事情就是首先设置它)。如果这是一个很长的下载,那么如果它不在后台继续,用户会很生气。 (这假设您正在下载东西,因为用户请求它。)
【讨论】:
感谢您的建议。我的应用程序将有另一个处理下载内容的对象。所以在 applicationDidEnterBackground 委托中。我可以只调用 __block UIBackgroundTaskIdentifier backgroundTask; backgroundTask = [应用程序 beginBackgroundTaskWithExpirationHandler: ^ [应用程序 endBackgroundTask: backgroundTask];背景任务 = UIBackgroundTask 无效; ]; ?当应用程序进入后台时,handlerBlock 将在 10 分钟后被调用。所以无论如何它都会 endBackgroundTaks。这个看起来更容易,但如果它浪费太多资源,我就不会了【参考方案2】:首先,最好在应用程序委托上进行此调用,以便可以关闭 NavigationController 中的 View。其次,用beginBackgroundTaskWithExpirationHandler:
标记后台处理的开始,用endBackgroundTask:
结束它,如下所示:
.h:
UIBackgroundTaskIdentifier bgTask;
.m:
- (void)sendPhoto:(UIImage *)image
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
];
NSLog(@"Sending picture...");
// Init async NSURLConnection
// ....
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
NSLog(@"Picture sent.");
UIApplication *app = [UIApplication sharedApplication];
if (bgTask != UIBackgroundTaskInvalid)
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
还要记住一件很重要的事情:
You have 10 minutes before ios terminates your app. You can check this time with
[app backgroundTimeRemaining
]
【讨论】:
感谢您的回答。但我不是很清楚。你的意思是我应该把那种代码放在控制器或 appDelegate 中? 或者我可以把这段代码放在 appDelegate - (void)applicationDidEnterBackground:(UIApplication *)application __block UIBackgroundTaskIdentifier backgroundTask; backgroundTask = [应用程序 beginBackgroundTaskWithExpirationHandler: ^ [应用程序 endBackgroundTask: backgroundTask];背景任务 = UIBackgroundTask 无效; ]; 是的,您只需将此代码放入您的应用程序委托中就可以了! 那么您的代码和我在评论中发布的代码有什么区别?以上是关于进入后台时的 NSURLConnection 最佳实践的主要内容,如果未能解决你的问题,请参考以下文章
应用程序进入后台时的popToRootViewController
有啥方法可以强制异步 NSURLConnection 在后台调用 connectionDidFinishLoading 吗?