重用的 GMSMapView 在第一次使用时有效,但不适用于任何进一步的 ViewControllers

Reused GMSMapView works on first use, but not on any further ViewControllers

我有几个显示地图的ViewController,所以我将公共地图逻辑提取到MapViewController:

import UIKit
import GoogleMaps
import GooglePlaces

class MapViewController : UIViewController {

var locationService: CLLocationManager!
var placesClient: GMSPlacesClient!
var marker: GMSMarker!
var camera: GMSCameraPosition!
var animatedMarkerImage: UIImage!
var markerImage1: UIImage!
var markerImage2: UIImage!
var markerImage3: UIImage!
var markerImage4: UIImage!
var markerImages: [UIImage]!

@IBOutlet weak var mapView: GMSMapView!

override func viewDidLoad() {
    super.viewDidLoad()

    locationService = LocationService.shared
    placesClient = GMSPlacesClient.shared()

    markerImage1 = UIImage(named: "Location 01@3x")
    markerImage2 = UIImage(named: "Location 02@3x")
    markerImage3 = UIImage(named: "Location 03@3x")
    markerImage4 = UIImage(named: "Location 04v@3x")
    markerImages = [markerImage1, markerImage2, markerImage3, markerImage4]
    animatedMarkerImage = UIImage.animatedImage(with: markerImages, duration: 1.5)

    do {
        if let styleURL = Bundle.main.url(forResource: "mapStyle", withExtension: "json") {
            mapView.mapStyle = try GMSMapStyle(contentsOfFileURL: styleURL)
        } else {
            NSLog("Unable to find mapStyle.json")
        }
    } catch {
        NSLog("One or more of the map styles failed to load. \(error)")
    }
  }
}

extension MapViewController : CLLocationManagerDelegate {


func startReceivingLocationChanges() {
    let authorizationStatus = CLLocationManager.authorizationStatus()

    if authorizationStatus != .authorizedWhenInUse && authorizationStatus != .authorizedAlways {
        return
    }

    if !CLLocationManager.locationServicesEnabled() {
        return
    }

    locationService.desiredAccuracy = kCLLocationAccuracyHundredMeters
    locationService.distanceFilter = 100.0
    locationService.startUpdatingLocation()
}

func locationManager(_ manager: CLLocationManager,  didUpdateLocations locations: [CLLocation]) {
    let location = locations.last!
    if marker == nil {
        camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: 14.0)
        marker = GMSMarker()
        let markerView = UIImageView(image: animatedMarkerImage)

        marker.position = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
        marker.iconView = markerView
        marker.map = mapView
        marker.appearAnimation = GMSMarkerAnimation.pop
        mapView.camera = camera
    } else {
        CATransaction.begin()
        CATransaction.setAnimationDuration(1.0)
        marker.position = location.coordinate
        CATransaction.commit()
    }
}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    if let error = error as? CLError, error.code == .denied {
        manager.stopUpdatingLocation()
        return
    }
    print("Location error: \(error)")
  }
}

我有三个不同的 ViewController 继承自此 MapViewController 并覆盖每个 viewDidLoad(),如下所示:

override func viewDidLoad() {
    super.viewDidLoad()
    locationService.delegate = self
    startReceivingLocationChanges()
}

地图和标记正确显示,并且相机移动到第一个 ViewController 的正确位置,但从地图 ViewController 继承的任何后续 ViewController 只显示英国。

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) 中放置一个断点显示第一个 ViewController 收到更新的位置,但后面的 ViewController 没有。

谁能告诉我我做错了什么?

因为 LocationService 公开了 CLLocationManager 的一个实例。它的 delegate 被分配给最后一个 viewController 加载的那个。这就是其他 viewController 没有收到更新的原因。我会让 LocationService 符合 CLLocationDelegate 并将其委托设置为自身。然后向 MapViewController 添加一个 updateLocation 函数来处理地图更新。

func updateLocation(location: CLLocation){
if marker == nil {
        camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: 14.0)
        marker = GMSMarker()
        let markerView = UIImageView(image: animatedMarkerImage)

        marker.position = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
        marker.iconView = markerView
        marker.map = mapView
        marker.appearAnimation = GMSMarkerAnimation.pop
        mapView.camera = camera
    } else {
        CATransaction.begin()
        CATransaction.setAnimationDuration(1.0)
        marker.position = location.coordinate
        CATransaction.commit()
    }
}

在您的 LocationService 中通过调用 updateLocation

更新控制器
func locationManager(_ manager: CLLocationManager,  didUpdateLocations locations: [CLLocation]) {
    let location = locations.last!
    viewController1.updateLocation(location: location)
    viewController2.updateLocation(location: location)
    viewController3.updateLocation(location: location)
}

另一种方法是给每个 MapViewController 一个不同的 CLLocationManager 实例(不共享),但这并没有实现您重用的想法。由于 CLLocationManager 正在访问设备上的单个位置服务,因此 CLLocationManager 的每个实例将执行相同的工作 3 次。希望这会有所帮助。