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
相关产品推荐
相关产品推荐

