You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UIRepresentable封装的MapKit中添加网络获取的大量标注

核心调整思路

  1. 数据直接存在你已有的DataModel中即可,只需给locations属性添加@Published修饰,网络请求更新数据后会自动触发UI刷新
  2. 标注更新逻辑放在updateUIView方法中实现,这是UIViewRepresentable接收SwiftUI状态变化的标准回调入口
  3. 用addAnnotations批量添加标注,配合系统自带的聚合能力优化800个标注的渲染性能

第一步:修改DataModel支持状态通知

确保网络请求更新位置数据后能通知视图刷新:

class DataModel: ObservableObject {
    // 加@Published修饰,数据变更时自动推送更新
    @Published var locations: [Location] = []
    
    // 你的网络请求逻辑示例
    func requestLocationData() {
        // 发起网络请求,解析返回的位置数组
        URLSession.shared.dataTask(with: URL(string: "你的接口地址")!) { [weak self] data, _, error in
            guard let data = data, error == nil, let list = try? JSONDecoder().decode([Location].self, from: data) else { return }
            DispatchQueue.main.async {
                // 赋值后自动触发UIMapView更新
                self?.locations = list
            }
        }.resume()
    }
}

第二步:修改UIMapView实现批量标注更新

struct UIMapView: UIViewRepresentable {
  
  @EnvironmentObject var dataModel: DataModel
  @EnvironmentObject var mapViewModel: MapViewModel

  func makeCoordinator() -> Coordinator { Coordinator() }
  
  func makeUIView(context: Context) -> MKMapView {
    let view = mapViewModel.mapView
    drawOverlayRing(view: view)
    view.delegate = context.coordinator
    // 提前注册标注视图,提升复用性能
    view.register(MKPinAnnotationView.self, forAnnotationViewWithReuseIdentifier: "pinAnnotation")
    view.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: "clusterAnnotation")
    return view
  }

  func updateUIView(_ uiView: MKMapView, context: Context) {
    // 先清理旧的自定义标注,保留用户定位标注
    uiView.annotations.forEach { annotation in
      guard !(annotation is MKUserLocation) else { return }
      uiView.removeAnnotation(annotation)
    }
    
    // 批量生成标注
    let annotations = dataModel.locations.map { location in
      let annotation = MKPointAnnotation()
      annotation.title = location.title
      annotation.coordinate = .init(latitude: location.latitude, longitude: location.longitude)
      return annotation
    }
    // 批量添加标注,性能远高于循环单个添加
    uiView.addAnnotations(annotations)
  }

  class Coordinator: NSObject, MKMapViewDelegate {
    func mapView(_ map: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
      // 跳过用户位置标注
      if annotation is MKUserLocation { return nil }
      
      // 处理聚合标注视图
      if let cluster = annotation as? MKClusterAnnotation {
          let clusterView = map.dequeueReusableAnnotationView(withIdentifier: "clusterAnnotation") as? MKMarkerAnnotationView ?? .init(annotation: annotation, reuseIdentifier: "clusterAnnotation")
          clusterView.glyphText = "\(cluster.memberAnnotations.count)"
          clusterView.markerTintColor = .systemBlue
          return clusterView
      }
      
      // 处理普通标注视图
      let identifier = "pinAnnotation"
      guard let pinView = map.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView else {
          let pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
          pinView.canShowCallout = true
          // 开启自动聚合,相同id的标注会自动聚合
          pinView.clusteringIdentifier = "locationGroup"
          return pinView
      }
      pinView.annotation = annotation
      return pinView
    }
  }

  // 保留你原有的绘制叠加层逻辑
  func drawOverlayRing(view: MKMapView) {
    // 原有实现不变
  }
}

性能优化说明

  • 开启clusteringIdentifier后系统会自动根据地图缩放级别聚合标注,缩小地图时显示聚合点、放大时拆分,大幅降低渲染压力
  • 800个标注用批量添加的方式不会出现卡顿,配合MKAnnotationView的复用机制,内存占用会维持在很低的水平
  • 无需手动管理标注生命周期,网络请求返回数据后只需赋值给DataModel.locations即可自动完成标注刷新

内容的提问来源于stack exchange,提问作者markb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 12:51:04