如果添加注释时缩放,则MKMapView崩溃 [英] MKMapView crashing if zooming while adding annotations

查看:52
本文介绍了如果添加注释时缩放,则MKMapView崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎我遇到了一个问题,如果我在更改地图的可见区域时添加注释,则可以可靠地导致MKMapView崩溃.我已经将导致其简化为一个非常简单的实现的代码煮沸了,我在这里重现它:

NSMutableArray *pointAnnotationArray = [[NSMutableArray alloc] init];
MKCoordinateRegion coordRegion = [mapViewOutlet region];
float randMax = 0.1;

for (int i = 0; i < 100; i++){
    float randomDeviation1 =  (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * randMax) - (randMax / 2);
    float randomDeviation2 =  (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * randMax) - (randMax / 2);

    MKPointAnnotation *point = [[MKPointAnnotation alloc] init];        
    CLLocationCoordinate2D pointLocation = CLLocationCoordinate2DMake(coordRegion.center.latitude + randomDeviation1, coordRegion.center.longitude + randomDeviation2);
    [point setCoordinate:pointLocation];    
    [pointAnnotationArray addObject: point];
}

[mapViewOutlet addAnnotations:[NSArray arrayWithArray:pointAnnotationArray]];

我在上面做的是在地图上添加100个点,这些点随机(足够)分布在MKMapView的可见区域内和周围.重现此问题的最简单方法是将代码设置为在计时器上运行(例如5秒钟后),然后抓取地图并开始放大和缩小一点,直到计时器运行为止.一旦感觉到它,您每次都会崩溃.在addAnnotations调用之前禁用mapViewOutlet上的用户交互似乎没有帮助. (也许是在用户处于手势中时它无法禁用用户交互,我想这是可以理解的.)

我的另一个问题是我没有足够的运气来跟踪崩溃–我没有太多的经验来导致崩溃不是直接在我自己的代码中发生的,因此我可能会错过一些明显的问题跟踪它的方法,但是我现在在main.mreturn UIApplicationMain行上遇到了一个无用的断点.我最好的猜测是,我们在MKMapView仅绘制可见注释的方式方面引起了一些问题–缩放导致可见区域发生变化,同时添加注释并且地图正在尝试确定要绘制的点. /p>

还有其他人看到过吗?关于如何避免这种情况的任何建议,而在添加注释的两端都没有将我的地图锁定在用户交互作用下很长时间的情况下?

忘记包括调用堆栈:

#0  0x3752a944 in objc_exception_throw ()
#1  0x3869dec0 in __NSFastEnumerationMutationHandler ()
#2  0x31929d46 in -[MKAnnotationContainerView _updateAnnotationViewPerspective] ()
#3  0x3192981a in -[MKMapView _updateScrollContainerView:] ()
#4  0x3192ff66 in -[MKMapView mapViewDidDraw:] ()
#5  0x391560b4 in -[VKMapCanvas didDrawView] ()
#6  0x3914d4a8 in -[VKScreenCanvas onTimerFired:] ()
#7  0x3914b4a8 in -[VKMapCanvas onTimerFired:] ()
#8  0x3914a346 in -[VKMainLoop displayTimerFired:] ()
#9  0x35ebe780 in CA::Display::DisplayLink::dispatch(unsigned long long, unsigned long long) ()
#10 0x35ebe6d8 in CA::Display::IOMFBDisplayLink::callback(__IOMobileFramebuffer*, unsigned long long, unsigned long long, unsigned long long, void*) ()
#11 0x34815fd6 in IOMobileFramebufferVsyncNotifyFunc ()
#12 0x370315ac in IODispatchCalloutFromCFMessage ()
#13 0x3866888a in __CFMachPortPerform ()
#14 0x386733e6 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#15 0x3867338a in __CFRunLoopDoSource1 ()
#16 0x3867220e in __CFRunLoopRun ()
#17 0x385e523c in CFRunLoopRunSpecific ()
#18 0x385e50c8 in CFRunLoopRunInMode ()
#19 0x3591e33a in GSEventRunModal ()
#20 0x379d5290 in UIApplicationMain ()
#21 0x0005aff4 in main at /Users/Sydin/App/main.m:16

解决方案

在添加新注解时,似乎对可见注解进行了某种更改,这可能是MKMapView中的问题,因为它可能在做它在辅助线程中的更新(有点像这样).我要做的是响应以下两个MKMapViewDelegate方法:

  • mapView:regionWillChangeAnimated:
  • mapView:regionDidChangeAnimated:

首先,将一个标志(将地图指定为用户正在移动的标志)设置为YES.在第二个中,将标志设置为NO.然后,每当您要添加新的注释时,请选中该标志.如果它是NO,则可以立即更新.如果它是YES,则将注释添加到可变集合中.在mapView:regionDidChangeAnimated:中,在清空该集合之前,将该集合中的所有注释添加到地图视图中.

即使这不是一个很好的解决方案,也应该可以解决该问题.您可以在Xcode中打开断点窗格,然后单击添加"按钮,然后选择异常断点",以便在应用崩溃时获得确切的行,而不是main.m.

It looks like I'm running into an issue where I can reliably cause my MKMapView to crash if I'm adding annotations while the map's visible region is being changed. I've boiled the code that is causing it down to a pretty simple implementation, and I'm reproducing it here:

NSMutableArray *pointAnnotationArray = [[NSMutableArray alloc] init];
MKCoordinateRegion coordRegion = [mapViewOutlet region];
float randMax = 0.1;

for (int i = 0; i < 100; i++){
    float randomDeviation1 =  (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * randMax) - (randMax / 2);
    float randomDeviation2 =  (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * randMax) - (randMax / 2);

    MKPointAnnotation *point = [[MKPointAnnotation alloc] init];        
    CLLocationCoordinate2D pointLocation = CLLocationCoordinate2DMake(coordRegion.center.latitude + randomDeviation1, coordRegion.center.longitude + randomDeviation2);
    [point setCoordinate:pointLocation];    
    [pointAnnotationArray addObject: point];
}

[mapViewOutlet addAnnotations:[NSArray arrayWithArray:pointAnnotationArray]];

What I'm doing above is adding 100 points on the map that are distributed randomly (enough) in and around the MKMapView's visible region. The easiest way to reproduce this is to set this code to run on a timer (say after 5 seconds), then grab the map and start zooming in and out a bit until the timer's run. Once you get a feel for it you can get a crash every time. Disabling user interaction on mapViewOutlet before the addAnnotations call doesn't seem to help. (Perhaps it isn't able to disable user interaction while the user is mid-gesture, which is understandable I suppose.)

My other problem is that I'm not having much luck tracing the crash – I don't have a lot of experience causing crashes that aren't happening directly in my own code, so I might be missing out on some obvious way to trace it, but I'm currently getting an unhelpful breakpoint on the return UIApplicationMain line in main.m. My best guess is that we're causing some issues with how the MKMapView only draws visible annotations – the zooming is causing that visible region to change, while annotations are being added and the map is trying to determine which points to draw.

Has anyone else seen this? Any suggestions on how to avoid it, without locking my map down from user interaction for some significant length of time on either end of my annotation addition?

Edit: Forgot to include the call stack:

#0  0x3752a944 in objc_exception_throw ()
#1  0x3869dec0 in __NSFastEnumerationMutationHandler ()
#2  0x31929d46 in -[MKAnnotationContainerView _updateAnnotationViewPerspective] ()
#3  0x3192981a in -[MKMapView _updateScrollContainerView:] ()
#4  0x3192ff66 in -[MKMapView mapViewDidDraw:] ()
#5  0x391560b4 in -[VKMapCanvas didDrawView] ()
#6  0x3914d4a8 in -[VKScreenCanvas onTimerFired:] ()
#7  0x3914b4a8 in -[VKMapCanvas onTimerFired:] ()
#8  0x3914a346 in -[VKMainLoop displayTimerFired:] ()
#9  0x35ebe780 in CA::Display::DisplayLink::dispatch(unsigned long long, unsigned long long) ()
#10 0x35ebe6d8 in CA::Display::IOMFBDisplayLink::callback(__IOMobileFramebuffer*, unsigned long long, unsigned long long, unsigned long long, void*) ()
#11 0x34815fd6 in IOMobileFramebufferVsyncNotifyFunc ()
#12 0x370315ac in IODispatchCalloutFromCFMessage ()
#13 0x3866888a in __CFMachPortPerform ()
#14 0x386733e6 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#15 0x3867338a in __CFRunLoopDoSource1 ()
#16 0x3867220e in __CFRunLoopRun ()
#17 0x385e523c in CFRunLoopRunSpecific ()
#18 0x385e50c8 in CFRunLoopRunInMode ()
#19 0x3591e33a in GSEventRunModal ()
#20 0x379d5290 in UIApplicationMain ()
#21 0x0005aff4 in main at /Users/Sydin/App/main.m:16

解决方案

It looks like some kind of problem with changes to the visible annotations while you're adding new ones — probably a problem in MKMapView, since it's probably doing its updates in a secondary thread (it's finicky like that). What I would do is respond to the following two MKMapViewDelegate methods:

  • mapView:regionWillChangeAnimated:
  • mapView:regionDidChangeAnimated:

In the first, set a flag that designates the map as being moved by the user to YES. In the second, set the flag to NO. Then, whenever you want to add new annotations, check the flag. If it's NO, then you're fine to update immediately. If it's YES, add your annotations to a mutable set. In mapView:regionDidChangeAnimated:, add any annotations in that set to the map view before emptying the set.

This should fix the problem, even if it's not an elegant solution. You can open the breakpoint pane in Xcode and click the add button, then select "Exception Breakpoint" so that when your app crashes, you get the exact line instead of main.m.

这篇关于如果添加注释时缩放,则MKMapView崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆