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

Google Places自动补全:如何批量获取各地点邮编?

解决方案

核心问题是需要批量处理异步的fetchPlace请求,原代码仅处理了第一个预测结果的详情请求,且错误地将该结果的坐标/邮编复用给了所有预测项。我们可以通过DispatchGroup来管理多个异步请求,待所有请求完成后再统一组装Place数组返回。

修改后的完整代码

public func findPlaces(
    query: String,
    completion: @escaping (Result<[Place], Error>) -> Void
) {
    let filter = GMSAutocompleteFilter()
    filter.types = ["geocode"]
    filter.countries = ["US"]
    
    client.findAutocompletePredictions(
        fromQuery: query,
        filter: filter,
        sessionToken: nil
    ) { results, error in
        guard let results = results, error == nil else {
            completion(.failure(PlacesError.failedToFind))
            return
        }
        
        // 初始化调度组和结果存储数组
        let dispatchGroup = DispatchGroup()
        var places: [Place] = []
        var fetchErrors: [Error] = []
        
        // 遍历所有预测结果,逐个发起详情请求
        for result in results {
            dispatchGroup.enter()
            
            self.client.fetchPlace(
                fromPlaceID: result.placeID,
                placeFields: [.coordinate, .addressComponents],
                sessionToken: nil
            ) { googlePlace, error in
                defer { dispatchGroup.leave() } // 请求完成后必须调用leave
                
                if let error = error {
                    fetchErrors.append(error)
                    return
                }
                
                guard let googlePlace = googlePlace else {
                    fetchErrors.append(PlacesError.failedToGetCoordinates)
                    return
                }
                
                // 解析邮编
                let zipCode = googlePlace.addressComponents?
                    .first(where: { $0.types.contains("postal_code") })?
                    .name ?? ""
                
                // 生成坐标对象
                let coords = PlaceCoords(withCoords: googlePlace.coordinate)
                
                // 生成当前预测项对应的Place对象
                let place = Place(
                    name: result.attributedPrimaryText.string,
                    identifier: result.placeID,
                    detail: Utils.shared.removeCountryFromPlace(string: result.attributedFullText.string),
                    coords: coords,
                    zipcode: zipCode
                )
                
                places.append(place)
            }
        }
        
        // 所有请求完成后统一处理结果
        dispatchGroup.notify(queue: .main) {
            // 错误策略1:只要有一个请求失败就返回错误
            if !fetchErrors.isEmpty {
                completion(.failure(fetchErrors.first ?? PlacesError.failedToGetCoordinates))
                return
            }
            
            // 错误策略2:忽略失败的请求,仅返回成功获取的Place数组
            // completion(.success(places))
            
            completion(.success(places))
        }
    }
}

// 补充错误枚举(如果之前未定义)
enum PlacesError: Error {
    case failedToFind
    case failedToGetCoordinates
}

关键改动说明

  • 用DispatchGroup跟踪所有fetchPlace请求的生命周期,确保所有请求完成后再组装结果
  • 遍历每个自动补全预测结果,为每个结果单独发起详情请求,避免复用单个结果的坐标/邮编
  • 维护错误数组,可灵活选择错误处理逻辑(全部失败才返回/忽略失败项)
  • 通过defer确保每个请求完成后调用dispatchGroup.leave(),防止调度组永久等待

注意事项

  • 注意Google Places API的调用配额,批量请求会消耗更多配额,建议结合session token优化请求
  • 可根据业务需求调整错误处理策略,比如允许部分失败仅返回成功的Place对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 11:30:41