その通りです。完了ハンドラーは、フェッチが実際に完了したときにのみ呼び出す必要があります。UIBackgroundFetchResultNewData
そうしないと、接続が完了する前に iOS がアプリケーションをスリープ状態に戻してしまう可能性があり、アプリケーションはそれまでに対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