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

Swift环境下HERE Map SDK中NMACoreRouter无法在循环中使用的问题

解决NMACoreRouter循环调用路线计算时第二次请求报错的问题

我之前也碰到过一模一样的问题,你这个情况的核心问题出在异步请求的生命周期管理和NMACoreRouter实例的重复创建上,咱们一步步拆解解决:

问题根源

  1. 重复创建CoreRouter实例:你在每次调用calculateRouteLength时都重新初始化了coreRouter = NMACoreRouter(),而calculateRoute是异步方法——当第二次循环执行时,新的CoreRouter实例会覆盖之前的,导致第一个请求的回调上下文丢失,直接触发错误。
  2. 并发请求被拦截:HERE Map SDK的路由接口默认不允许同时发起多个未完成的请求,循环里的并行调用会被SDK判定为非法请求,返回NMARoutingError。

解决方案

1. 复用单个CoreRouter实例

把CoreRouter的初始化移到循环和方法外面,比如在类的初始化方法或viewDidLoad里只创建一次,避免每次请求都新建实例覆盖旧的。

2. 用串行队列控制请求顺序

因为异步请求不能并行发起,我们用一个串行队列来依次处理每个店铺的路线计算请求,确保上一个请求完成后再发起下一个,避免并发冲突。

修改后的完整代码示例

// 类属性部分:只初始化一次CoreRouter,创建串行队列
var coreRouter: NMACoreRouter!
var mapRoute: NMAMapRoute?
private let routeCalculationQueue = DispatchQueue(label: "com.yourapp.route.calculation")

override func viewDidLoad() {
    super.viewDidLoad()
    // 只在初始化时创建一次CoreRouter实例
    coreRouter = NMACoreRouter()
}

// 循环调用部分:用串行队列串行发起请求
for shop in pickedShopData {
    routeCalculationQueue.async { [weak self] in
        guard let self = self else { return }
        self.calculateRouteLength(startLat: self.curentUserGeo.latitude,
                                  startLong: self.curentUserGeo.longitude,
                                  endLat: shop.shopLat,
                                  endLong: shop.shopLong)
    }
}

// 路线计算方法:移除重复的CoreRouter初始化,添加主队列更新UI
func calculateRouteLength(startLat: Double, startLong: Double, endLat: Double, endLong: Double) {
    /* 定义路线起点终点 */
    let startPoint = NMAGeoCoordinates(latitude: startLat, longitude: startLong)
    let endPoint = NMAGeoCoordinates(latitude: endLat, longitude: endLong)
    let routePlan = [startPoint, endPoint]
    
    /* 配置路由模式 */
    let routeMode = NMARoutingMode()
    routeMode.transportMode = NMATransportMode.scooter
    routeMode.routingOptions.insert(NMARoutingOption.avoidHighway)
    routeMode.routingType = NMARoutingType.fastest
    routeMode.resultLimit = 3

    coreRouter.calculateRoute(withStops: routePlan, routingMode: routeMode, { [weak self] (result, error) in
        guard let self = self else { return }
        // 所有UI操作必须回到主队列执行
        DispatchQueue.main.async {
            guard let route = result?.routes?.first, error == NMARoutingError.none else {
                print("路由计算错误:\(error ?? NMARoutingError.unknown)")
                return
            }
            
            // 更新地图上的路线
            if let tempMapRoute = self.mapRoute {
                self.mapView?.remove(mapObject: tempMapRoute)
            }
            guard let newMapRoute = NMAMapRoute(route) else {
                return
            }
            self.mapRoute = newMapRoute
            print("路线长度:\(newMapRoute.route.length)")
        }
    })
}

额外注意事项

  • 用[weak self]捕获self,避免循环引用导致的内存泄漏
  • 所有涉及地图UI的操作(比如添加/移除路线)必须放在主队列,HERE SDK的UI组件不支持在子线程操作
  • 如果你的数据量很大,也可以考虑使用SDK的批量路由接口(如果提供的话),不过串行队列是最稳妥的兼容方案

内容的提问来源于stack exchange,提问作者Minh Đức Hoàng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 19:59:10