重用的 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 次。希望这会有所帮助。
我有几个显示地图的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 次。希望这会有所帮助。