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

如何用Swift与Mapbox获取已下载离线地图包列表?解析KVO相关问题

嘿,我之前在做Mapbox离线地图功能的时候也碰到过这个问题,文档里只提了KVO但没给示例确实有点坑!下面给你详细说下具体怎么实现获取已下载离线包列表,两种方式都给你整理好了:

方法一:使用传统KVO监听(兼容所有Swift版本)

Mapbox的MGLOfflineStorage共享实例的packs属性是延迟加载的,所以必须通过KVO监听它的变化才能拿到完整列表。具体实现步骤如下:

  1. 创建管理类(或直接在ViewController中),确保类继承自NSObject(KVO需要NSObject子类支持)
  2. 添加KVO监听packs键路径,加上.initial选项,这样添加监听时会立即触发回调,拿到当前已有的离线包
  3. 实现KVO回调方法,在里面获取并处理离线包列表
  4. 销毁时务必移除观察者,避免内存泄漏

代码示例:

import Mapbox

class OfflineMapManager: NSObject {
    private let offlineStorage = MGLOfflineStorage.shared
    
    override init() {
        super.init()
        // 添加KVO监听,.initial确保初始加载时触发回调
        offlineStorage.addObserver(self, forKeyPath: "packs", options: [.initial, .new], context: nil)
    }
    
    deinit {
        // 务必移除观察者,防止内存泄漏
        offlineStorage.removeObserver(self, forKeyPath: "packs", context: nil)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        // 确认是监听packs属性的变化
        guard keyPath == "packs", let storage = object as? MGLOfflineStorage else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }
        
        // 这里就能拿到所有已下载(包括正在下载)的离线包列表了
        let allPacks = storage.packs
        
        // 遍历处理每个离线包的信息
        print("当前已下载离线包数量:\(allPacks.count)")
        for pack in allPacks {
            print("---")
            print("包名称:\(pack.name ?? "未命名")")
            print("包覆盖范围:\(pack.boundingBox)")
            print("包状态:\(self.stateDescription(for: pack.state))")
            print("下载进度:\(pack.progress)")
        }
    }
    
    // 辅助方法:把MGLOfflinePackState转成易读的描述
    private func stateDescription(for state: MGLOfflinePackState) -> String {
        switch state {
        case .inactive:
            return "已完成下载"
        case .active:
            return "正在下载"
        case .completed:
            return "下载完成(旧版本状态)"
        case .invalid:
            return "无效包"
        @unknown default:
            return "未知状态"
        }
    }
}
方法二:使用Combine框架(更简洁,适合iOS 13+)

如果你的项目已经使用Combine框架(比如SwiftUI项目或者iOS 13及以上),可以用更现代的方式监听属性变化,不用手动管理观察者:

import Mapbox
import Combine

class OfflineMapManager {
    private let offlineStorage = MGLOfflineStorage.shared
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        // 用Combine监听packs属性的变化
        offlineStorage.publisher(for: \.packs)
            .sink(receiveValue: { [weak self] packs in
                guard let self = self else { return }
                print("离线包列表更新:")
                for pack in packs {
                    print("包名:\(pack.name ?? "未命名") | 状态:\(self.stateDescription(for: pack.state))")
                }
            })
            .store(in: &cancellables)
    }
    
    private func stateDescription(for state: MGLOfflinePackState) -> String {
        switch state {
        case .inactive:
            return "已完成"
        case .active:
            return "下载中"
        case .completed:
            return "已完成"
        case .invalid:
            return "无效"
        @unknown default:
            return "未知"
        }
    }
}
额外注意事项
  • 如果你只需要获取一次已下载列表而不需要监听变化,在KVO回调里拿到列表后可以立即移除观察者
  • 要删除某个离线包,可以调用pack.remove(completionHandler:)方法,删除后packs列表会自动更新,KVO/Combine会触发回调
  • 确保你的Mapbox SDK是最新版本,不同版本的MGLOfflinePackState可能有细微差异,建议参考对应版本的官方文档

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:47:27