MKLocalSearchの短期集中実行(過剰リクエスト)に注意
MKLocalSearchを使うと、Apple Mapsが提供する地図上の地物情報をマップビューなしで検索できます。リクエストに応じてAppleのサーバーが地物名や緯度経度などの情報を返してくれます。
ただし、このAPIには制限があり、短期間にリクエストが集中するとエラーを返すことがあります。ドキュメント上ではあまり言及されていないようですが、具体的には 60秒間に50回より多くのリクエストが生じると、サーバーがエラーを返します。
その際にXcodeのコンソールには次のようなエラーが吐かれます。
Throttled "PlaceRequest.REQUEST_TYPE_SEARCH" request: Tried to make more than 50 requests in 60 seconds, will reset in 14 seconds -
Error Domain=GEOErrorDomain
Code=-3 "(null)"
UserInfo={
details=(
{
intervalType = short;
maxRequests = 50;
"throttler.keyPath" = "app:<BUNDLE_IDENTIFIER>/0x20301/short(default/any)";
timeUntilReset = 14;
windowSize = 60;
}
),
requestKindString=PlaceRequest.REQUEST_TYPE_SEARCH,
timeUntilReset=14,
requestKind=769
}
UserInfoの中身がわかりやすいように私の方で一部整形をかけていますが、Dictionary<String : Any>形式のオブジェクトにエラー情報が含まれています。
しかし、Swiftコード上でキャッチできるエラーオブジェクトはこの情報(GEOErrorDomain)ではなく、別のMKErrorDomainなるより簡素なエラーオブジェクトが入ってきます。なので、コンソールに現れるこれらの情報を使って何かロジックを構築して機能させるといったことは難しそうです。
なお、この制限は少なくともアプリ単位で計測されているようです。<BUNDLE_IDENTIFIER>の部分には実際のアプリのバンドルIDが入ります。これが、複数の端末で同時にリクエストした場合にも「アプリ単位」になるのか、アプリは同じでもデバイスごとに独立して計測されるのか(インスタンスごとなのか)、どちらになるのかは調査しきれていません。
(例えばthrottler.keyPathの0x20301の部分がユーザー環境のインスタンスやデバイスなどの固有番号を表しているのであれば、これはあまり気にする必要はなさそうなのですが)
とりあえずの対処としては、次のようになります。
- 短期間に多くのリクエストを送信しない仕組みを作る(目安:60秒間に50回を上限)
- エラーに含まれる詳細情報をあてにしない
- エラーが生じたら、数十秒待機する
Discussion