C# 等待CLGeocoder.GeocodeAddressAsync永不返回
我试图测试苹果公司的前向地理编码服务的准确性,以涵盖我们数据模型上的纬度/经度丢失或无效,但我们仍然知道物理地址的罕见情况。Monotouch提供了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块中不会
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
,因此此更改会影响调用者<代码>异步将通过代码库“增长”,这是正常的。有关更多信息,请参阅我的