【iOS】ジオフェンスに21個以上regionを登録したい場合


iOSのジオフェンスに21個以上登録したい

iOSのジオフェンス機能は同時に20箇所までしかモニタリングしてくれません(Androidは100箇所とか…)。21箇所以上は登録できないので、まずは近くの20件を登録しておいて、移動や時間が空いたタイミングで再度近隣の20件を登録するという方法を取る必要があります。
移動を検知して新しくregionを登録する際は、以前登録したregionを破棄する必要があります。
破棄する場合は

CLLocationManager *locationManager = [[CLLocationManager alloc] init];
[[locationManager monitoredRegions] enumerateObjectsUsingBlock:^(__kindof CLRegion * _Nonnull region, BOOL * _Nonnull stop) {
    [locationManager stopMonitoringForRegion:region];
}];

ですべて削除可能です。
ジオフェンスをすべて削除したあとにジオフェンスを新規に登録すればOK

再度ジオフェンスにregionを登録するタイミング

ジオフェンスに登録するタイミングですが、アプリがバックグラウンドに入ってしまってからの話なので次のタイミングがいいかと思っています。
1. Significant-Change Location
2. ジオフェンスに入った・出たタイミング

①の場合はジオフェンス登録箇所が少なく、それぞれのregionがバラバラな場合
②の場合はregionがある程度密集している場合
に適しているのではないかと思います。

ジオフェンスの登録に失敗...

上記方法で、ジオフェンスを登録→削除→登録とするとmonitoringDidFailForRegionが呼ばれ
Error Domain=kCLErrorDomain Code=5 "(null)"
という結果が返ってきてしまいました。このエラー内容からは実際には何が原因でエラーが発生しているかはわからないのですが、調べると21箇所以上登録した際に発生することが多いようです。
ただ今回の場合はしっかりregionを全部削除してから登録しているので問題がないはず…

しかしregionの削除コードで以下を試してみたところ…

CLLocationManager *locationManager = [[CLLocationManager alloc] init];
[[locationManager monitoredRegions] enumerateObjectsUsingBlock:^(__kindof CLRegion * _Nonnull region, BOOL * _Nonnull stop) {
    [locationManager stopMonitoringForRegion:region];
}];
// 同じコードの繰り返し
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
[[locationManager monitoredRegions] enumerateObjectsUsingBlock:^(__kindof CLRegion * _Nonnull region, BOOL * _Nonnull stop) {
    [locationManager stopMonitoringForRegion:region]; // 呼ばれないと思っていたら呼ばれることがある
}];

全削除の直後に削除コードを呼び出しても登録済みのregionが取得できてしまいました。そしてこれは取得できたりできなかったり。

ここからは推測でしかないんですが
Location Manager stopMonitoringForRegion Not Working
このstackoverflowの投稿を見ると同じ現象に遭遇している人が多いみたいです。推測するにregionの削除は同期的に行われるわけではなく、どこかのキューに入れられて随時削除されていくという方法が取られているようです。

必ず登録に成功させたい場合の一つのやり方としてmonitoringDidFailForRegionの中で失敗したregionを再登録する方法があります。

-(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
    [_locationManager startMonitoringForRegion:region];
}

ただこのコードに1点問題があって、21箇所以上ジオフェンスのregionを登録しようとすると無限ループすることになってしまいます。
間違いなく20箇所以下しか登録しないと保証できればこれで間違いなく登録できるはずです。

現状そこまで失敗する確率が高くなく、いくつかのタイミングでジオフェンスを登録できるようにしているため現状では失敗時に再登録処理はしないつもりです。他に良い方法があれば教えていただきたいですm(_ _)m