何时在应用程序中调用completionHandler:performFetchWithCompletionHandler:当后台提取为异步时?

时间:2013-10-16 21:33:05

标签: ios asynchronous ios7 multitasking

我有一个应用程序,可以在后台获取的帮助下在后台获取内容。

因此,如果应该进行后台提取,则调用我的application:performFetchWithCompletionHandler:方法。在这个方法中,我使用NSURLConnection来异步获取内容。

在我当前的实现中,我只启动请求,然后使用completionHandler调用UIBackgroundFetchResultNewData。我知道这不可能是正确的。所以我的问题是,当completionHandler方法中的异步请求完成时,如何正确调用connection:didReceiveData:

1 个答案:

答案 0 :(得分:15)

你是对的 - 你应该只在你的获取实际完成时调用完成处理程序。否则,iOS可能会在连接完成之前让您的应用程序重新进入休眠状态,并且应用程序实际上无法在此之前确定UIBackgroundFetchResultNewDataUIBackgroundFetchResultNoDataUIBackgroundFetchResultFailed。你怎么知道你的联系会成功?

您需要保持completionHandler并仅在连接完成后调用它。很可能你会想要为你的委托添加一个实例变量,将完成处理程序复制到那里,并在你完成后调用它。

除此之外:connection:didReceiveData:不表示请求已结束。根据文件:

  

作为连接发送,以递增方式加载数据。

     

[...]

     

委托应该连接每个数据对象的内容   交付以构建URL加载的完整数据。

您可能会收到任意数量的电话,而网址连接的最终结果是所有电话的累积。

编辑:通过创建正确类型的实例变量并块复制到其中来存储块。块具有不寻常的语义,因为与其他类型的Objective-C对象不同,它们最初是在堆栈上创建的。净效果只是你总是copy。如果你在复制时它们在堆栈中,那么它们最终会堆在堆上。如果它们已经在堆上,那么副本就可以作为保留,因为无论如何块总是不可变的。

所以:

@implementation XXMDYourClass
{
    // syntax follow the C rule; read from the centre outwards
    void (^_completionHandler)(UIBackgroundFetchResult);
}

- (id)initWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    self = [super init];

    if(self)
    {
        // keep the block by copying it; release later if
        // you're not using ARC
        _completionHandler = [completionHandler copy];
    }

    return self;
}

- (void)somethingThatHappensMuchLater
{
     _completionHandler(UIBackgroundFetchResultWhatever);
}

@end