Приложение iOS получает дросселирование от локальных запросов

Я реализую автозаполнение (один поиск на новый добавленный символ) в приложении, которое ищет адреса, и я продолжаю получать MKErrorDomain error 3, что составляет MKErrorLoadingThrottled. Эта ошибка, согласно Apple dev, возникает, когда

Данные не были загружены, поскольку дросселирование данных действует. Эта ошибка может возникнуть, если приложение делает частые запросы на данные по короткий период времени.

Я точно знаю, сколько запросов выполняется, по одному для каждого нового шаблона в поисковом запросе (так же, как вы ожидаете, что автозаполнение будет работать). Конечно, я быстрый типер, но я могу превзойти лимит после 10 или 15 запросов, кажется абсурдным. Глядя на следующие две исходные ссылки, я не понимаю, почему я продолжаю получать дросселирование.

В соответствии с Apple dev:

Нет ограничений на количество запросов для каждого приложения или идентификатора разработчика, поэтому хорошо написано приложения, которые работают правильно, не должны испытывать никаких проблем. Однако, дросселирование может происходить в плохо написанном приложении, которое создает чрезвычайно большое количество запросов.

и как Джеймс Ховард сказал на WWDC:

И еще одно, о чем я хочу поговорить, - это ограничения использования на этом API. Итак, я рад сообщить, что нет приложения или разработчика широкие пределы использования идентификатора. Итак, если у вас есть приложение, в котором много пользователей, и вы хотите много сделать запросов, что штраф.

Это сработает.

И дросселирование, которое у нас есть, - это действительно первая строка защита от багги-приложений. Таким образом, если вы отправляете запросы маршрутов или запросы локального поиска в бесконечный цикл, у вас есть ошибка, в конце концов вы собираетесь получить задушил.

Но если вы делаете что-то разумное, вы говорите, о, я собираюсь просто сделать направления в ответ на ввод пользователя, и вы знаете, что можете сделать несколько потому что мы показали им этот пример.

Как мы сделали запрос двух направлений в ответ на один пользовательский ввод, это здорово. Но вы знаете, делаете ли вы 10 000 каждый раз, когда пользователь нажимает на экран, тогда вы собираетесь задушить. Но, просто держите его разумным, и все будет в порядке.

Любые идеи, почему это происходит?

Ответ 1

Для автозаполнения требуются специальные API. MapKit не предлагает такой интерфейс. Простое отключение десятков запросов к обычным API поиска вызывает огромную нагрузку.

В основном у вас есть два варианта:

  • Перейдите в Google Адреса. У них есть специальный API автозаполнения мест. Существует даже полная библиотека для iOS на GitHub.

  • Уменьшить количество запросов, например. отправив запрос только в том случае, если пользователь приостановил ввод в течение 300 мс и только в том случае, если предыдущий запрос не выдался. Но это все еще не гарантирует, что Apple не будет подавлять ваши запросы.

Ответ 2

MKLocalSearch в первую очередь предназначен для поиска точек интереса (предприятий и т.д.) в пределах границ карты. CLGeocoder предназначен для структурированного поиска адресов и местоположений.

Документация CLGeocoder указывает, что запросы CLGeocoder ограничены по скорости, а документация содержит рекомендации о том, как быть хорошим гражданином.

Особо следует отметить первый пункт в руководящих принципах: "Отправить не более одного запроса на любое действие пользователя". Это также следует применять к MKLocalSearch - если у вас одновременно есть несколько запросов в полете, вы, скорее всего, получите дросселирование.

Это довольно просто реализовать: перед отправкой нового MKLocalSearchRequest отмените все ожидающие запросы. Это имеет большое значение для реализации автозаполнения, как вы описываете: если пользователь вводит 4-й символ, вам, вероятно, не нужен запрос или ответ для третьего символа.

Ответ 3

Запустите приложение в инструменте Time Profiler и посмотрите, сколько вызовов этого метода выполняется при вводе.

Ответ 4

Я просто написал Helper в Swift, чтобы помочь сделать предложение с API Apple MapKit. Он вызывает запрос поиска, когда пользователь перестает вводить запрос. https://github.com/ArniDexian/GeocodeHelper

Использование довольно просто:

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    GeocodeHelper.shared.decode(searchText.trimmed(), completion: { [weak self](places) -> () in
        self?.dataSource.locations = places
        self?.tableView.reloadData()
        return
        })
}