在带有NSOperation的iOS 7中使用Background Fetch调用completionHandler时

Pie*_*ero 8 objective-c ios7

我想在我的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)

所以我的问题是,我怎么能处理好completionHandlerNSOperation

Ale*_*MDC 7

您必须在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)

您会注意到,即使在调用完成块之前退出该方法,也不会记录警告.


M. *_*ani 6

我的应用程序也有类似的情况.我所做的是将完成处理程序传递给我的单例,每当我的代码路径在操作中结束时,无论是成功还是错误,我都会检查是否有对完成块的引用.如果是这样,我只是用适当的结果调用完成处理程序,如果没有,这意味着我不处于后台获取模式.不要忘记在病房之后将完成处理程序的引用设置为单个nil,因为它可能会在后续操作中欺骗您的实例.我也做了其他的事情,因为在开始我的操作之前,在后台获取时强制性的30秒超时,我检查我是否处于后台获取模式,如果是这样,我安排一个25秒的计时器(保证的5秒阈值)并自己处理这个情况.如果你不这样做,并且你的应用程序在调用完成处理程序上的次数超过30秒就会失败,那么你最终会阻止你的应用程序在用户设备上进行后台获取.祝好运


Sco*_*ets 1

在某些时候,您的应用程序会知道何时完成了新数据的获取和处理。这可以是每当新文件存储到磁盘时、新记录插入核心数据时,或者网页完成加载时。

一旦发生这种情况,您必须确定是否确实有新数据,然后使用正确的参数调用完成处理程序。这很可能意味着您必须将完成处理程序传递给其他对象。startCheckOnCloud将变为startCheckOnCloudWithCompletionHandler:,并且如果该方法不是实际执行提取的方法,则将完成处理程序传递给执行startCheckOnCloudWithCompletionHandler:提取的调用的方法。