C# 等待CLGeocoder.GeocodeAddressAsync永不返回

C# 等待CLGeocoder.GeocodeAddressAsync永不返回,c#,xamarin.ios,xamarin,async-await,core-location,C#,Xamarin.ios,Xamarin,Async Await,Core Location,我试图测试苹果公司的前向地理编码服务的准确性,以涵盖我们数据模型上的纬度/经度丢失或无效,但我们仍然知道物理地址的罕见情况。Monotouch提供了CLGeocoder.GeocodeAddress(String,CLGeocodeCompletionHandler)和GeocodeAddressAsync(String),但当我调用它们时,永远不会调用completionHandler,也不会返回async方法 我的应用程序日志中没有任何内容表明存在问题,将调用封装在try-catch块中不会

我试图测试苹果公司的前向地理编码服务的准确性,以涵盖我们数据模型上的纬度/经度丢失或无效,但我们仍然知道物理地址的罕见情况。Monotouch提供了
CLGeocoder.GeocodeAddress(String,CLGeocodeCompletionHandler)
GeocodeAddressAsync(String)
,但当我调用它们时,永远不会调用completionHandler,也不会返回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;
    }
private void ReloadPlacemarks()
{
//列表以保存返回空/无效坐标的所有位置标记
列表地理列表=新列表();
mapView.ClearPlacemarks();
列表位置标记=新列表();
if(serviceCallViewModel.ActiveServiceCall!=null){
var serviceCall=serviceCallViewModel.ActiveServiceCall;
if(serviceCall.dblLatitude!=0&&serviceCall.dblLongitude!=0){
Add(serviceCall.ToPlacemark());
}否则{
//将其添加到地理代码列表中
添加(serviceCall);
}
}
foreach(serviceCallViewModel.ServiceCalls中的var serviceCall){
if(serviceCall.dblLatitude!=0&&serviceCall.dblLongitude!=0){
Add(serviceCall.ToPlacemark());
}否则{
//将其添加到地理代码列表中
添加(serviceCall);
}
}
如果(placemarks.Count>0){
mapView.AddPlacemarks(placemarks.ToArray());
}
如果(geoList.Count>0){
//尝试转发街道地址的地理编码
foreach(地理列表中的ServiceCalls包装器){
ServiceCallWrapper serviceCall=GeocodeServiceCallAddressAsync。结果;
mapView.AddPlacemark(serviceCall.ToPlacemark());
}
}
}
专用异步任务GeocodeServiceCallAddressAsync(ServiceCallWrapper s)
{
CLGeocoder geo=新的CLGeocoder();
字符串addr=s.address+“”+s.city+“”+s.state+“”+s.zip;
Console.WriteLine(“正在尝试转发地址为“+addr”的服务调用UID:+s.call_UID+”的地理代码);
//应用程序挂在这个位置
CLPlacemark[]结果=等待geo.GeocodeAddressAsync(addr);
//代码更新纬度和经度(省略)
返回s;
}

您的问题是这一行:

ServiceCallWrapper serviceCall = GeocodeServiceCallAddressAsync (s).Result;
通过调用
Task.Result
,您正在导致死锁。我对此进行了充分的解释,但其要点是
await
在产生控件时(默认情况下)将捕获一个“上下文”,并将使用该上下文来完成
async
方法。在本例中,“上下文”是UI上下文。因此,当响应传入时,UI线程被阻塞(等待
结果
),并且
异步
方法无法继续,因为它正在等待在UI线程上运行

解决方案是始终使用
async
。换句话说,用
Wait
替换每个
Task.Result
Task.Wait

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

请注意,
void ReloadPlacemarks
现在是
Task ReloadPlacemarksAsync
,因此此更改会影响调用者<代码>异步将通过代码库“增长”,这是正常的。有关更多信息,请参阅my。

您的问题是这一行:

ServiceCallWrapper serviceCall = GeocodeServiceCallAddressAsync (s).Result;
通过调用
Task.Result
,您正在导致死锁。我对此进行了充分的解释,但其要点是
await
在产生控件时(默认情况下)将捕获一个“上下文”,并将使用该上下文来完成
async
方法。在本例中,“上下文”是UI上下文。因此,当响应传入时,UI线程被阻塞(等待
结果
),并且
异步
方法无法继续,因为它正在等待在UI线程上运行

解决方案是始终使用
async
。换句话说,用
Wait
替换每个
Task.Result
Task.Wait

private async Task ReloadPlacemarksAsync()
{
  ...
  ServiceCallWrapper serviceCall = await GeocodeServiceCallAddressAsync (s);
  ...
}
请注意,
void ReloadPlacemarks
现在是
Task ReloadPlacemarksAsync
,因此此更改会影响调用者<代码>异步将通过代码库“增长”,这是正常的。有关更多信息,请参阅我的