【问题标题】:When call completionHandler with Background Fetch in iOS 7 with NSOperation当使用 NSOperation 在 iOS 7 中使用 Background Fetch 调用 completionHandler
【发布时间】:2013-11-23 16:25:07
【问题描述】:

我想在我的 iOS 应用程序中集成 Background Fetch,我已经在项目的功能中启用了 Background Fetch,然后我插入了这个:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

以最小间隔启用后台提取,然后在 App 委托中插入委托方法:

-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    NSLog(@"Call fetch iCloud");
    [[MySingleton sharedManager] startCheckOnCloud];
}

我的问题是这个,我知道我必须这样称呼:

completionHandler(UIBackgroundFetchResultNewData);

在某处,我看到了很多在 performFetchWithCompletionHandler 委托方法中插入该完成处理程序的示例,但在该方法中,我在 Singleton 中调用 NSOperation,该操作检查 iCloud 文件夹并进行一些更改在Sqlite DB,如果我这样做:

    -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
        NSLog(@"Call fetch iCloud");
        [[MySingleton sharedManager] startCheckOnCloud];
        completionHandler(UIBackgroundFetchResultNewData);
    }

操作开始并执行任何操作,可能是因为系统使其立即休眠,而不是如果我删除了 completionHandler 给我这个警告:

Warning: Application delegate received call to -application:performFetchWithCompletionHandler: but the completion handler was never called.

所以我的问题是,我如何处理 completionHandlerNSOperation

【问题讨论】:

    标签: objective-c ios7


    【解决方案1】:

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

    你会注意到警告没有被记录,尽管方法在调用完成块之前就退出了。

    【讨论】:

    • 伙计,这个的 swift 版本是什么!
    • @JayprakashDubey func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * Int64(NSEC_PER_SEC)), dispatch_get_main_queue()) { completionHandler(UIBackgroundFetchResult.NewData) } }
    • 您提到强参考跟踪真是太棒了。解决了我的问题!
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      在某些时候,您的应用会知道何时完成获取和处理新数据。这可能是每当一个新文件被存储到磁盘,新记录被插入到 Core Data 中,或者当一个网页完成加载时。

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

      【讨论】:

        【解决方案4】:

        我也有这个问题,我终于解决了我的错误是,由于在fetch回调中存在异步操作,当你开始使用__block UIBackgroundFetchResult赋值给这个:

        UIBackgroundFetchResult __block result = UIBackgroundFetchResultNoData;
        result = UIBackgroundFetchResultNoData; 
        post: return; return; because, "did not lead to finally, the method is called," completionHandler (result); "
        

        所以出现了一个错误:“completion handler was never called”,“return;”摆脱了最终调用方法:“completionHandler(result);”没有错误。总结下,就是必须调用的方法:completionHandler();不能错。

        谢谢。

        【讨论】:

        • 非常感谢您纠正错误~。 @JaggenSWE
        猜你喜欢
        • 1970-01-01
        • 2014-04-22
        • 2013-10-25
        • 2014-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多