Подтвердить что ты не робот

Как лучше всего загружать местоположения для MapView с веб-сервера

У меня есть 2000 местоположений в веб-базе данных, которые пользователь должен иметь возможность выбирать на карте. Я могу попросить веб-базу данных предоставить мне только определенное количество мест, происходящих из текущего местоположения.

Чтобы сделать все гладким и элегантным, я бы сначала создал экземпляр MKMapView, запустил CLLocationManager и подождал, пока не получу didUpdateLocations. Затем я попытаюсь получить данные из базы данных с помощью обработчика завершения.

Должен ли я

a) получить сразу все данные

b) получить данные в маленьких кусках или кусках?

Как это лучший способ?

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    self.gotoCurrentLocation()
    if let userLocation = manager.location {
        GroundHelper.getAllGroundLocations(userLocation) { self.handleWaypoints($0!) }
    }
}

private func handleWaypoints(grounds: [Ground]) {
    mapView.addAnnotations(grounds)
}

// MARK: - Helper Methods

typealias GPXCompletionHandler = ([Ground]?) -> Void

class func getAllGroundLocations(userlocation: CLLocation, completionHandler: GPXCompletionHandler)  {

    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
    dispatch_async(dispatch_get_global_queue(priority, 0), { ()->() in
        var results = RestApiManager.sharedInstance.getGPS(userlocation, limit: 50)

        // return first 50 results
        dispatch_async(dispatch_get_main_queue(), {

            var grounds = [Ground]()
            for result in results {
                let (_,jsonGround) = result
                let ground = Ground(json:jsonGround)
                grounds.append(ground)
            }
            completionHandler(grounds)
        })

        // get the rest
        results = RestApiManager.sharedInstance.getGPS(userlocation)

        // return them
        dispatch_async(dispatch_get_main_queue(), {

            var grounds = [Ground]()
            for result in results {
                let (_,jsonGround) = result
                let ground = Ground(json:jsonGround)
                grounds.append(ground)
            }
            completionHandler(grounds)

        })
    })
}
4b9b3361

Ответ 1

Получение всех данных сразу не масштабируется. Вы можете заставить его работать своевременно с 2000 записей, но что, если набор данных растет? Можете ли вы справиться с 3000? 5000? 10000 аннотаций?

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

Таким образом, рекомендуемый подход для отличного пользовательского интерфейса заключается в локальном кэшировании результатов. Вы можете сделать это, если у вас есть локальная база данных (например, Core Data), или вы можете сделать это с помощью NSCache.

При таком подходе вы будете поражать сервер новыми запросами, когда пользователь перемещается по карте, но количество возвращаемых результатов может быть ограничено 20, 50 или 100 (что дает вам наибольшее количество данных, а будучи очень отзывчивым).

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

Ребята из http://realm.io имеют довольно приятное видео, которое объясняет этот подход: https://www.youtube.com/watch?v=hNDNXECD84c Хотя вам не нужно использовать свою мобильную базу данных (Realm), вы можете получить представление о архитектуре и дизайне приложений.

Ответ 2

Прежде всего, вы должны подумать, что в MKMapView одновременно будут помещаться аннотации 2000. Возможно, вам стоит попытаться восстановить только те места, которые находятся на карте, которую вы представляете.

После этого в вашем коде вы добавляете аннотации каждый раз, когда вызывается didUpdateLocations. Вы удаляете старые аннотации в любом другом месте?. Если аннотации не изменяются и находятся на карте, вы не должны добавлять их снова.

Я думаю, что хороший подход должен быть:

1.- Вызывается первый раз didUpdateLocations: спросите свою веб-службу для аннотаций, которые соответствуют расстоянию, равному двум раз области, отображающей вашу карту. Сохраните это местоположение как locationOrigin, сохраните это расстояние как distanceOrigin

2.- В следующий раз вызывается didUpdateLocations: Если расстояние, перемещенное из текущего местоположения в locationOrigin, равно половине расстояния Origin. Вы должны снова запросить веб-службу, обновите переменные "Origin" и добавьте только новые аннотации в mapView.

3.- Если regionWillChange вызывается (MKMapViewDelegate): пользователь масштабирует, перемещает карту или поворачивает устройство... простой подход - это перезагрузка аннотаций, как если бы мы были на шаге 1. Более разумный подход заключается в добавлении распознавателя жестов для определения того, масштабируется ли пользователь (в этом случае аннотации не изменяются) или масштабирование или перемещение (аннотации могут меняться)

Ответ 3

Загрузите их в куски рядом с текущими местоположениями пользователя, если пользователь уменьшит нагрузку на другой кусок, если пользователь переместит карту, загрузит еще один кусок и так далее. таким образом ваше приложение будет масштабироваться лучше, если ваши аннотации становятся все более похожими на аннотации 1M.

Ответ 4

Я действительно написал приложение, которое может разместить 7000 аннотаций на MKMapView без проблем с производительностью... и на iPad 1. Вам действительно не нужно беспокоиться о карте.

Единственным ограничивающим фактором, о котором я могу думать, является то, как долго будет выполняться сетевой вызов и будет ли это проблемой. В моем случае я вытаскивал адреса из базы данных контактов, геокодировал их, а затем сохранял lat-longs в основных данных. Да, геокодирование 7000 адресов берет навсегда, но как только у вас есть лат-longs, ставя их на карту, это простой материал, и код карты может справиться с этим просто...