Swift实现Google Maps仅刷新标记而非整个地图的方法
解决Google Maps仅刷新车辆标记而非整个地图的问题
你的核心问题是每次定时器触发时都重新创建了新的标记(Marker)和路线(Polyline),而非更新已有实例,导致地图上堆积大量元素,看起来像是整个地图在刷新。下面是具体的修改方案:
步骤1:将Marker和Polyline改为类成员变量
首先在类里声明全局的标记和路线对象,这样不需要每次都重新创建实例:
var driverLatitude: Double? var driverLongitude: Double? var pickupLatitude: Double? // 假设你已定义该变量 var pickupLongitude: Double? // 假设你已定义该变量 // 新增全局的标记和路线对象,仅初始化一次 var vehicleMarker: GMSMarker? var routePolyline: GMSPolyline?
步骤2:初始化Marker样式(仅执行一次)
在viewDidLoad里完成车辆标记的样式初始化,后续只需要更新位置即可:
override func viewDidLoad() { self.tripLocDetailsTimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(tripLocDetailCustomrWebserviceCall), userInfo: nil, repeats: true) // 初始化车辆标记的样式,仅执行一次 let cabIM = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 15)) cabIM.image = UIImage(named: "bike_color") vehicleMarker = GMSMarker() vehicleMarker?.iconView = cabIM vehicleMarker?.infoWindowAnchor = CGPoint(x: 0.44, y: 0.40) vehicleMarker?.tracksViewChanges = false vehicleMarker?.map = self.mapView }
步骤3:修改showingThePath()方法,仅更新已有实例
现在只需要更新标记的位置,以及按需更新路线路径,不再重复创建新的Marker和Polyline:
func storingDataOftripLocDetails(_ data: TripLocationDetailsResponse){ self.driverLatitude = data.locationDetails?.driverDetails?.pickupLatitude self.driverLongitude = data.locationDetails?.driverDetails?.pickupLongitude self.showingThePath() } func showingThePath(){ // 用guard let避免强制解包导致崩溃 guard let driverLat = driverLatitude, let driverLng = driverLongitude, let pickupLat = pickupLatitude, let pickupLng = pickupLongitude else { return } // 仅更新车辆标记的位置 let vehicleLocation = CLLocationCoordinate2D(latitude: driverLat, longitude: driverLng) vehicleMarker?.position = vehicleLocation // 构建路线请求URL let origin = "\(driverLat),\(driverLng)" let destination = "\(pickupLat),\(pickupLng)" guard let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)") else { return } URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) in if let error = error { print("获取路线失败:\(error.localizedDescription)") return } guard let data = data else { print("无路线数据返回") return } do{ let json = try JSONSerialization.jsonObject(with: data, options:.allowFragments) as! [String : Any] print(json) guard let status = json["status"] as? String, status == "OK" else { print("路线请求状态异常") return } guard let routes = json["routes"] as? [[String:Any]], let firstRoute = routes.first else { print("无可用路线") return } OperationQueue.main.addOperation({ guard let routeOverviewPolyline = firstRoute["overview_polyline"] as? [String:String], let points = routeOverviewPolyline["points"], let path = GMSPath.init(fromEncodedPath: points) else { return } // 如果已有路线实例,仅更新路径;否则创建新的路线 if let polyline = self.routePolyline { polyline.path = path } else { self.routePolyline = GMSPolyline(path: path) self.routePolyline?.strokeColor = .gray self.routePolyline?.strokeWidth = 3.0 self.routePolyline?.map = self.mapView } }) }catch let error as NSError{ print("解析路线数据失败:\(error.localizedDescription)") } }).resume() }
额外优化建议
- 减少API调用:如果终点(pickup位置)固定,可以不用每次定时器触发都请求路线,只在司机位置变化时更新标记即可
- 定时器生命周期管理:在
viewWillDisappear中调用tripLocDetailsTimer?.invalidate(),避免内存泄漏 - 错误处理增强:可以给用户添加友好的错误提示,比如路线请求失败时显示Toast
内容的提问来源于stack exchange,提问作者Bhanuteja
相关产品推荐
相关产品推荐

