跳转到正文
YGJoon 技术博客

iOS MapKit 地图选址:请求竞态与镜头状态同步

发布于:
·711 字 · 约 2 分钟·作者:
梳理地图中心查询、关键词搜索、切换地区和设备定位之间的状态关系,并阻止过期候选结果覆盖当前选择。
iOS MapKit 地图选址:请求竞态与镜头状态同步文章封面
目录

示例代码均为匿名化改写,用于说明模式;地图与地理编码依赖由调用方注入。

地图页存在多份候选状态

地图位置选择页面同时处理已有地区、地图中心、附近候选、搜索结果和用户点选项。地图移动可能触发附近查询;搜索期间的镜头变化不应覆盖搜索结果;切换城市则需要清理旧地区的候选和搜索状态。

每次异步查询都分配新的请求标识。只有仍属于当前请求、且没有取消的响应才能更新候选列表。附近查询和关键词搜索使用不同依赖入口,便于分别处理加载状态、错误和结果。

@MainActor
final class SearchResultsModel<Item: Sendable> {
    private(set) var items: [Item] = []
    private(set) var error: Error?
    private(set) var isLoading = false
    private var requestID = UUID()

    func search(
        _ query: String,
        using lookup: (String) async throws -> [Item]
    ) async {
        let currentID = UUID()
        requestID = currentID
        error = nil
        isLoading = true
        defer {
            if requestID == currentID { isLoading = false }
        }
        do {
            let result = try await lookup(query)
            guard !Task.isCancelled, requestID == currentID else { return }
            items = result
        } catch let lookupError {
            guard !Task.isCancelled, requestID == currentID else { return }
            error = lookupError
        }
    }
}

程序移动与用户拖动要区分

代码把镜头移动到定位点、地区中心或候选地址后,地图也会回报一次区域变化。如果把程序变化当作用户拖动,就会立即再发一遍附近查询。一次性跳过标记能消除这类重复请求。

页面还可以记录上次附近查询坐标,只有地图移动超过业务阈值才刷新。模型负责响应顺序和选中状态,视图层负责地图相机与交互节流,避免两类职责混在一个状态对象中。

程序调用地图相机也可能触发区域变化回调;需要识别预期中的程序更新,再决定是否查询附近内容。搜索态和浏览态最好用互斥状态表达,避免旧的附近结果覆盖关键词结果。

确认结果应成为明确值

点选候选时先使旧请求失效,再保存选择。确认后向上层返回名称、地区、地址和坐标组成的值对象。定位成功、无数据、取消和失败应分别表达,让页面根据权限状态显示合适的提示。

这种结构既能让地图和列表保持同步,也便于不启动地图 UI 就测试搜索切换、旧结果丢弃和候选确认。


分享这篇文章:


相关文章

上一篇
iOS Core Location 首页刷新:手动选址优先与位置阈值
下一篇
iOS 订单状态矩阵:后端状态与页面操作映射