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

Swift中如何避免局部变量Snapshotter被提前释放?

解决Mapbox Snapshotter作为局部变量时onStyleLoaded不触发的问题

问题描述

将Snapshotter定义为类变量时,startSnapshot函数可正常生成地图快照;但改为局部变量后,snapshotter.onStyleLoaded.observeNext回调始终不触发,代码失效。尝试过DispatchGroup、Semaphore等方式等待任务完成,要么阻塞UI线程要么无效果,需要让snapshotter保持局部变量的前提下解决该问题。

解决方案

修改startSnapshot方法,关键是保留订阅引用并确保Snapshotter实例在流程完成前不被释放,修改后的代码如下:

private func startSnapshot() {
    let options = MapSnapshotOptions(size: CGSize(width: view.bounds.size.width, height: view.bounds.height), pixelRatio: 4)
    
    let snapshotter = Snapshotter(options: options)
    snapshotter.styleURI = .dark
    snapshotter.setCamera(to: CameraOptions(center: CLLocationCoordinate2D(latitude: 51.180885866921386, longitude: 16.26129435178828), zoom: 4))
    
    // 保存style加载完成的订阅引用
    let styleLoadedCancelable = snapshotter.onStyleLoaded.observeNext { [weak self, weak snapshotter] _ in
        guard let snapshotter = snapshotter else { return }
        snapshotter.start { overlayHandler in
            let context = overlayHandler.context
            
            let berlin = overlayHandler.pointForCoordinate(CLLocationCoordinate2D(latitude: 52.53, longitude: 13.38))
            let krakow = overlayHandler.pointForCoordinate(CLLocationCoordinate2D(latitude: 50.06, longitude: 19.92))
            
            context.setStrokeColor(UIColor.yellow.cgColor)
            context.setLineWidth(6.0)
            context.setLineCap(.round)
            context.move(to: berlin)
            context.addLine(to: krakow)
            context.strokePath()
        } completion: { [weak self, weak styleLoadedCancelable] result in
            // 完成后取消订阅并移除引用
            styleLoadedCancelable?.cancel()
            self?.cancelables.remove(styleLoadedCancelable)
            
            switch result {
            case .success(let image):
                self?.snapshotView.image = image
            case .failure(let error):
                print("Error generating snapshot: \(error)")
            }
        }
    }
    // 将订阅加入cancelables集合,持有引用避免被销毁
    cancelables.insert(styleLoadedCancelable)
}

原因说明

  • 原代码中onStyleLoaded.observeNext返回的AnyCancelable未被保存,函数执行完毕后订阅会立即被取消,导致回调无法触发;
  • Snapshotter作为局部变量时,若无额外引用持有,函数执行完成后会被ARC自动释放,后续的style加载流程直接中断。

通过将订阅的AnyCancelable加入cancelables集合,保留了订阅的引用,确保回调能正常触发;闭包中通过弱引用捕获Snapshotter,配合订阅的持有,可保证实例在整个快照生成流程完成前不会被释放。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:05:55