MapView按title排序后的标注添加至标注数组时顺序发生改变问题
问题原因
- 你排序的数据源是
mapView.annotations,这个属性是MKMapView内部维护的无序只读集合,除了你自己添加的标注外,还可能包含系统自动生成的标注(比如用户定位的MKUserLocation实例),不仅原始顺序不受你控制,空title的系统标注还会干扰你的排序逻辑。 - 调用
addAnnotations的传入顺序不会改变mapView.annotations的返回顺序,MKMapView内部不会保留你添加标注的顺序,不管你按什么顺序传入,后续读取mapView.annotations的顺序都是乱的。 - 你原有代码的排序闭包参数名容易引发逻辑混淆,且没有过滤无效的系统标注,也会导致排序结果不符合预期。
解决方案
核心思路是自己单独维护一份和picker排序完全对齐的annotation数组,完全不依赖mapView.annotations的返回顺序做联动:
- 基于你已经排好序的分支数组,直接生成对应annotation数组,这份数组由你自己持有,顺序和picker的选项顺序100%匹配。
- 将自己持有的annotation数组添加到地图即可,不需要关心地图内部的存储顺序,picker联动时直接从自己持有的数组里取对应索引的annotation。
代码示例
// 你已经排序好的分支数组,和picker展示顺序完全一致 let sortedBranches: [Branch] = // 原有排序后的分支数组 // 自己持有和分支数组顺序完全对齐的annotation数组 var mySortedAnnotations: [MKAnnotation] = [] for branch in sortedBranches { let ann = MKPointAnnotation() ann.title = branch.title ann.coordinate = CLLocationCoordinate2D(latitude: branch.latitude, longitude: branch.longitude) mySortedAnnotations.append(ann) } // 添加到地图,不需要关心添加顺序 mapView.addAnnotations(mySortedAnnotations) // Picker选中事件联动逻辑 func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { // 直接从自己持有的有序数组取对应annotation,不会出现索引不匹配问题 let target = mySortedAnnotations[row] // 缩放并弹出气泡 mapView.selectAnnotation(target, animated: true) mapView.setRegion(MKCoordinateRegion(center: target.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000), animated: true) }
如果确实需要从地图现有标注中过滤并排序,使用以下代码:
let sortedAnnotations = mapView.annotations // 过滤掉系统生成的用户定位标注 .filter { !($0 is MKUserLocation) } .sorted { a, b in guard let aTitle = a.title as? String, let bTitle = b.title as? String else { return false } return aTitle < bTitle }
内容的提问来源于stack exchange,提问作者Kegham K.
相关产品推荐
相关产品推荐

