你是对的——你应该只在你的 fetch 真正完成时才调用完成处理程序。否则,iOS 可能会在连接完成之前让您的应用程序重新进入睡眠状态,并且应用程序实际上不应该能够确定UIBackgroundFetchResultNewData
与UIBackgroundFetchResultNoData
或UIBackgroundFetchResultFailed
在那之前无论如何。你怎么知道你的连接会成功?
您需要保留 completionHandler 并仅在连接完成后调用它。您很可能希望将一个实例变量添加到您的委托,将完成处理程序复制到那里,并在完成后调用它。
旁白:connection:didReceiveData:
不表示请求的结束。根据文档:
作为连接发送以增量方式加载数据。
[...]
委托应连接交付的每个数据对象的内容,以构建 URL 加载的完整数据。
您可能会收到任意数量的呼叫,而 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