我想在我的iOS应用程序中集成Background Fetch,我在项目的功能中启用了Background Fetch,然后我插入了这个:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
Run Code Online (Sandbox Code Playgroud)
要以最小间隔启用后台提取,然后在App委托中插入委托方法:
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(@"Call fetch iCloud");
[[MySingleton sharedManager] startCheckOnCloud];
}
Run Code Online (Sandbox Code Playgroud)
我的问题是这个,我知道我必须这样称呼:
completionHandler(UIBackgroundFetchResultNewData);
Run Code Online (Sandbox Code Playgroud)
在某个地方,我看到很多示例在performFetchWithCompletionHandler委托方法中插入了completionHandler ,但在该方法中我调用了NSOperation一个Singleton,该操作检查che iCloud文件夹并在a中进行一些更改Sqlite DB,如果我这样做:
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(@"Call fetch iCloud");
[[MySingleton sharedManager] startCheckOnCloud];
completionHandler(UIBackgroundFetchResultNewData);
}
Run Code Online (Sandbox Code Playgroud)
操作开始并做任何事情,可能是因为系统让它立即进入休眠状态,而如果我删除了completionHandler,请给我这个警告:
Warning: Application delegate received call to -application:performFetchWithCompletionHandler: but the completion handler was never called.
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,我怎么能处理好completionHandler与NSOperation?
您必须在30秒内调用完成处理程序,但在执行查询时不必阻止主线程.
看来内部UIKit检测到您没有存储对completionHandler的强引用,然后记录该警告.如果你执行这样简单的事情:
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
// Start asynchronous NSOperation, or some other check
// Ideally the NSOperation would notify when it has completed, but just for
// illustrative purposes, call the completion block after 20 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
// Check result of your operation and call completion block with the result
completionHandler(UIBackgroundFetchResultNewData);
});
}
Run Code Online (Sandbox Code Playgroud)
您会注意到,即使在调用完成块之前退出该方法,也不会记录警告.
我的应用程序也有类似的情况.我所做的是将完成处理程序传递给我的单例,每当我的代码路径在操作中结束时,无论是成功还是错误,我都会检查是否有对完成块的引用.如果是这样,我只是用适当的结果调用完成处理程序,如果没有,这意味着我不处于后台获取模式.不要忘记在病房之后将完成处理程序的引用设置为单个nil,因为它可能会在后续操作中欺骗您的实例.我也做了其他的事情,因为在开始我的操作之前,在后台获取时强制性的30秒超时,我检查我是否处于后台获取模式,如果是这样,我安排一个25秒的计时器(保证的5秒阈值)并自己处理这个情况.如果你不这样做,并且你的应用程序在调用完成处理程序上的次数超过30秒就会失败,那么你最终会阻止你的应用程序在用户设备上进行后台获取.祝好运
在某些时候,您的应用程序会知道何时完成了新数据的获取和处理。这可以是每当新文件存储到磁盘时、新记录插入核心数据时,或者网页完成加载时。
一旦发生这种情况,您必须确定是否确实有新数据,然后使用正确的参数调用完成处理程序。这很可能意味着您必须将完成处理程序传递给其他对象。startCheckOnCloud将变为startCheckOnCloudWithCompletionHandler:,并且如果该方法不是实际执行提取的方法,则将完成处理程序传递给执行startCheckOnCloudWithCompletionHandler:提取的调用的方法。