c# - await CLGeocoder.GeocodeAddressAsync 从不返回

标签 c# xamarin.ios xamarin async-await core-location

我正在尝试测试 Apple 的正向地理编码服务的准确性,以涵盖我们数据模型中的纬度/经度缺失或无效但我们仍然知道实际地址的罕见情况。 Monotouch 提供了 CLGeocoder.GeocodeAddress(String, CLGeocodeCompletionHandler)GeocodeAddressAsync(String) 但是当我调用它们时,completionHandler 永远不会被调用,异步方法也永远不会返回。

我的应用程序日志中没有任何内容表明有问题,并且将调用包含在 try-catch block 中也没有出现任何异常。项目选项中启用了 map 集成。缺少捕获网络流量(无论如何都可能是 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;
    }

最佳答案

你的问题是这一行:

ServiceCallWrapper serviceCall = GeocodeServiceCallAddressAsync (s).Result;

调用 Task<T>.Result ,你造成了僵局。我对此进行了充分解释 on my blog ,但它的要点是 await将(默认情况下)在它放弃控制时捕获一个“上下文”,并将使用该上下文来完成 async方法。在这种情况下,“上下文”是 UI 上下文。因此,当响应到来时,UI 线程被阻塞(等待 Result),并且 async方法无法继续,因为它正在等待在 UI 线程上运行。

解决方案是使用async一路。换句话说,替换每个 Task<T>.ResultTask.Waitawait :

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

请注意您的 void ReloadPlacemarks现在是Task ReloadPlacemarksAsync ,因此此更改会影响您的来电者。 async将通过代码库“增长”,这是正常的。有关详细信息,请参阅我的 MSDN article on async best practices .

关于c# - await CLGeocoder.GeocodeAddressAsync 从不返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23701445/

相关文章:

c# - 线程函数的行为与我预期的不一样

xamarin - 使用 xamarin 在 VS15 上构建 ios 应用程序时出错

Android:EditText自动打开键盘,如何停止?

Xamarin 表格 : Cannot add RESX for globalization

c# - 锁定来自不同线程的方法范围的 "string"对象会阻止执行吗?

javascript - 如何将字典从 c#(服务器)传递到 javascript(客户端)

c# - 将输入添加到数组的构造函数

c# - 如何计算 linq to sql 查询中列值的总和?

ios - 将事件附加到接口(interface)但不使用具体类时,Monotouch 应用程序崩溃

C# PresentViewController 到 Storyboard 中的 View Controller