await CLGeocoder.GeocodeAddressAsync никогда не возвращается

1

Я пытаюсь проверить точность службы геокодирования Apple перед тем, чтобы покрыть редкий случай, когда широта/долгота у нас на нашей модели данных отсутствует или недействительна, но мы все еще знаем физический адрес. Monotouch предоставляет CLGeocoder.GeocodeAddress(String, CLGeocodeCompletionHandler) и GeocodeAddressAsync(String) но когда я их CLGeocoder.GeocodeAddress(String, CLGeocodeCompletionHandler) завершенияHandler никогда не вызывается, и метод async никогда не возвращается.

Ничто в моем журнале приложений не указывает на проблему, и включение вызова в блок try-catch не вызвало каких-либо исключений. Интеграция карт включена в параметрах проекта. Если не считать захвата сетевого трафика (это, вероятно, SSL), у меня нет идей.

Здесь код, который загружает метки и пытается выполнить геокодирование адресов:

    private void ReloadPlacemarks()
    {
        // list to hold any placemarks which come back with empty/invalid coordinates
        List<ServiceCallWrapper> geoList = new List<ServiceCallWrapper> ();

        mapView.ClearPlacemarks ();

        List<MKPlacemark> placemarks = new List<MKPlacemark>();
        if (serviceCallViewModel.ActiveServiceCall != null) {
            var serviceCall = serviceCallViewModel.ActiveServiceCall;
            if (serviceCall.dblLatitude != 0 && serviceCall.dblLongitude != 0) {
                placemarks.Add (serviceCall.ToPlacemark ());
            } else {
                // add it to the geocode list
                geoList.Add (serviceCall);
            }
        }

        foreach (var serviceCall in serviceCallViewModel.ServiceCalls) {
            if (serviceCall.dblLatitude != 0 && serviceCall.dblLongitude != 0) {
                placemarks.Add (serviceCall.ToPlacemark ());
            } else {
                //add it to the geocode list
                geoList.Add (serviceCall);
            }
        }

        if (placemarks.Count > 0) {
            mapView.AddPlacemarks (placemarks.ToArray ());
        }

        if (geoList.Count > 0) {

            // attempt to forward-geocode the street address
            foreach (ServiceCallWrapper s in geoList) {
                ServiceCallWrapper serviceCall = GeocodeServiceCallAddressAsync (s).Result;
                mapView.AddPlacemark (serviceCall.ToPlacemark());
            }
        }

    }

    private async Task<ServiceCallWrapper> GeocodeServiceCallAddressAsync(ServiceCallWrapper s)
    {
        CLGeocoder geo = new CLGeocoder ();
        String addr = s.address + " " + s.city + " " + s.state + " " + s.zip;
        Console.WriteLine ("Attempting forward geocode for service call UID: " + s.call_uid + " with address: " + addr);

                    //app hangs on this
        CLPlacemark[] result = await geo.GeocodeAddressAsync(addr);

                    //code updating latitude and longitude (omitted)

        return s;
    }
Теги:
xamarin
async-await
xamarin.ios
core-location

1 ответ

5
Лучший ответ

Ваша проблема в этой строке:

ServiceCallWrapper serviceCall = GeocodeServiceCallAddressAsync (s).Result;

Task<T>.Result, вы вызываете тупик. Я полностью объясняю это в своем блоге, но суть этого заключается в том, что await (по умолчанию) захватить "контекст", когда он даст управление, и будет использовать этот контекст для завершения async метода. В этом случае "контекст" представляет собой контекст пользовательского интерфейса. Таким образом, поток пользовательского интерфейса блокируется (ожидание Result), когда приходит ответ, и метод async не может продолжаться, потому что он ожидает выполнения в потоке пользовательского интерфейса.

Решение состоит в том, чтобы использовать async полностью. Другими словами, заменить каждую Task<T>.Result и Task.Wait с await:

private async Task ReloadPlacemarksAsync()
{
  ...
  ServiceCallWrapper serviceCall = await GeocodeServiceCallAddressAsync (s);
  ...
}

Обратите внимание, что ваши void ReloadPlacemarks теперь Task ReloadPlacemarksAsync, поэтому это изменение влияет на ваших абонентов. async будет "расти" через кодовую базу, и это нормально. Для получения дополнительной информации см. Статью MSDN о лучших методах async.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню