2015-04-03 64 views
3

我们的应用程序有一个过程,当用户放大到1500英尺时发生这种情况发生在放大时发生这种情况是因为我们的地图在那里聚焦的区域大约有4000个兴趣点。MKMapView - 在后台线程中添加注释

我们在这个系统中遇到的问题是,每当区域发生变化,我们都必须循环4000个POI,然后在用户正在查看的区域内添加这些POI。

该过程将整个应用程序冻结4-5秒,然后添加正确的POI。我们探讨其他方法可以做到这一点,并想出了一个解决方案,完全停止冻结:

func regionDidChange(mapView: MKMapView, animated: Bool) { 
    if (mapView.camera!.altitude <= 1500) { 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
      var stopsToAdd = [StopAnnotation]() 
      var stopsToRemove = [StopAnnotation]() 

      // Remove old POIs 
      for (var i = 0; i < self.mapView.annotations.count; i++) { 
       if (self.mapView.annotations[i].isKindOfClass(StopAnnotation)) { 
        let stopAnnotation: StopAnnotation! = self.mapView.annotations[i] as StopAnnotation 

        if (!MKMapRectContainsPoint(mapView.visibleMapRect, MKMapPointForCoordinate(stopAnnotation.coordinate))) { 
         stopsToRemove.append(stopAnnotation) 
        } 
       } 
      } 

      // Add new POIs 
      for (var i = 0; i < self.busStops.count; i++) { 
       if (!self.isStarredStop(self.busStops[i].atcocode)) { 
        if (MKMapRectContainsPoint(mapView.visibleMapRect, MKMapPointForCoordinate(self.busStops[i].position))) { 
         let stop: StopAnnotation! = StopAnnotation() 
         stop.setCoordinate(self.busStops[i].position) 
         stopsToAdd.append(stop) 
        } 
       } 
      } 

      // Add new POIs to map 
      dispatch_async(dispatch_get_main_queue()) { 
       self.mapView.removeAnnotations(stopsToRemove) 
       self.mapView.addAnnotations(stopsToAdd) 
      } 
     } 
    } 
} 

这种方法的问题是,我相信我们“犯法”。在做了一些研究之后,我认为在另一个线程中做这样的过程令人不敢恭维。但即使我不理睬这些建议,有时候也会发生崩溃。

崩溃发生在9号线:

if (self.mapView.annotations[i].isKindOfClass(StopAnnotation)) { 

错误:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSSetM addObject:]: object cannot be nil'

任何人都可以请帮我想出了一个替代解决方案,以确保应用程序运行流畅如没有上述崩溃?

+0

你应该在你的主UI线程执行注释相关的东西,而不是后台线程,因为注释添加和删除是用户界面的更新,你应该主要做这些UI线程。 – ztan 2015-04-03 16:24:04

+0

@ztan在主UI线程中进行这些更改意味着应用程序会冻结5-10秒,除非我误解?通过主UI线程你的意思是正常执行代码,而不是'dispatch_async'内? – user3605739 2015-04-03 16:27:12

+0

如果你尝试做API请求,那么你必须在后台线程中执行,但是你现在正在做的事情都是与UI相关的,所以你可以在主UI线程中执行它们。同时搜索你的文件,看看你是否在任何地方调用addObject方法。 – ztan 2015-04-03 16:42:19

回答

1

我相信这是线程之间的同步问题。在后台线程中,您尝试直接从地图视图访问注释,并且同时在主线程上添加/从地图视图中删除它们。

更改第一for循环到:

// Remove old POIs 

NSArray annotations = [elf.mapView.annotations copy]; 
MKMapRect visibleMapRect = mapView.visibleMapRect; 

for (var i = 0; i < annotations.count; i++) { 
    if (annotations[i].isKindOfClass(StopAnnotation)) { 
     let stopAnnotation: StopAnnotation! = annotations[i] as StopAnnotation 

     if (!MKMapRectContainsPoint(visibleMapRect, MKMapPointForCoordinate(stopAnnotation.coordinate))) { 
      stopsToRemove.append(stopAnnotation) 
     } 
    } 
} 
+0

此代码可能也会在[self.mapView.annotations copy]语句中崩溃,并且与该问题具有相同的异常。因此,不是一个可行的解决方案(尽管它可能会损失更少的时间) – 2016-02-17 10:11:00