MKAnnotation 视图转场
MKAnnotation View Segue
我有一组要显示在 MapView 上的地点。我创建了一个 MKAnnotationView 来显示一个右键。然后我显示一个 detailView 并通过 segue 传递数据,但它显示错误的位置。我认为我的 selectedAnnotations 有问题。用户在任何时候只能 select 一个注释。
整个Class
import UIKit
import MapKit
class MapViewController: UIViewController, PlacesModelDelegate, CLLocationManagerDelegate {
@IBOutlet weak var mapView: MKMapView!
var places = [Place]()
var model:PlacesModel?
var locationManager:CLLocationManager?
var lastKnownLocation:CLLocation?
var selectedAnnotation: Place?
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
// Set map properties
mapView.showsUserLocation = true
// Instantiate location manager
locationManager = CLLocationManager()
locationManager?.delegate = self
// Instantiate places model if it is nil
if model == nil {
model = PlacesModel()
model?.delegate = self
}
// Call get places
model?.getPlaces()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Functions
func plotPins() {
var pinsArray = [MKPointAnnotation]()
// Go through the array of places and plot them
for p in places {
// Create a pin
let pin = MKPointAnnotation()
// Set its properties
pin.coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(p.lat), longitude: CLLocationDegrees(p.long))
pin.title = p.name
pin.subtitle = p.getTypeName()
// Add it to the map
mapView.addAnnotation(pin)
// Store the pin in the pinsArray
pinsArray.append(pin)
}
// Center the map
mapView.showAnnotations(pinsArray, animated: true)
}
func displaySettingsPopup() {
// Create alert controller
let alertController = UIAlertController(title: "Couldn't find your location",
message: "Location Services is turned off on your device or the GuideBookApp doesn't have permission to find your location. Please check your Privacy settings to continue.",
preferredStyle: .alert)
// Create settings button action
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (alertAction) in
if let appSettings = URL(string: UIApplicationOpenSettingsURLString) {
UIApplication.shared.open(appSettings, options: [:], completionHandler: nil)
}
}
alertController.addAction(settingsAction)
// Create cancel button action
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
// Show the alert
present(alertController, animated: true, completion: nil)
}
// MARK: - Button Handlers
@IBAction func locationButtonTapped(_ sender: UIButton) {
// Check if location services are enabled
if CLLocationManager.locationServicesEnabled() {
// They're enabled, now check the authorization status
let status = CLLocationManager.authorizationStatus()
if status == .authorizedAlways || status == .authorizedWhenInUse {
// Has permission
locationManager?.startUpdatingLocation()
// Center the map on last location
if let actualLocation = lastKnownLocation {
mapView.setCenter(actualLocation.coordinate, animated: true)
}
}
else if status == .denied || status == .restricted {
// Doesn't have permission
// Tell user to check settings
displaySettingsPopup()
}
else if status == .notDetermined {
// Ask the user for permission
locationManager?.requestWhenInUseAuthorization()
}
}
else {
// Locations services are turned off
// Tell user to check settings
displaySettingsPopup()
}
}
// MARK: - PlacesModelDelegate Methods
func placesModel(places: [Place]) {
// Set places property
self.places = places
// Plot the pins
plotPins()
}
// MARK: - CLLocationManagerDelegate Methods
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
if let actualLocation = location {
// Create a pin
let pin = MKPointAnnotation()
pin.coordinate = CLLocationCoordinate2D(latitude: actualLocation.coordinate.latitude, longitude: actualLocation.coordinate.longitude)
// Center the map, only if it's the first time locating the user
if lastKnownLocation == nil {
mapView.setCenter(actualLocation.coordinate, animated: true)
}
// Save the pin
lastKnownLocation = actualLocation
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// See what the user has answered
if status == .denied {
// Tell user that this app doesn't have permission. They can change it in their settings
displaySettingsPopup()
}
else if status == .authorizedWhenInUse || status == .authorizedAlways {
// Permission granted
locationManager?.startUpdatingLocation()
}
}
}
extension MapViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "marker"
var view: MKMarkerAnnotationView
view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
return view
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
performSegue(withIdentifier: "mapSegue", sender: view)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedRow = mapView.selectedAnnotations.endIndex
let selectedPlace = places[selectedRow]
let detailModel = DetailModel()
detailModel.place = selectedPlace
let detailVC = segue.destination as! VenueDetailViewController
detailVC.model = detailModel
}
}
放置模型
import UIKit
protocol PlacesModelDelegate {
func placesModel(places:[Place])
}
class PlacesModel: NSObject, FirebaseManagerDelegate {
// Properties
var delegate:PlacesModelDelegate?
var firManager:FirebaseManager?
func getPlaces() {
// Get places from FirebaseManager
if firManager == nil {
firManager = FirebaseManager()
firManager!.delegate = self
}
// Tell firebase manager to fetch places
firManager!.getPlacesFromDatabase()
}
func checkDataVersion() {
// Get version from FirebaseManager
if firManager == nil {
firManager = FirebaseManager()
firManager!.delegate = self
}
firManager!.getVersionFromDatabase()
}
// MARK: - FirebaseManager Delegate Methods
func firebaseManager(places: [Place]) {
// Notify the delegate
if let actualDelegate = delegate {
actualDelegate.placesModel(places: places)
}
}
}
FirebaseManager
import UIKit
import Firebase
@objc protocol FirebaseManagerDelegate {
@objc optional func firebaseManager(places:[Place])
@objc optional func firebaseManager(metaDataFor place:Place)
@objc optional func firebaseManager(imageName:String, imageData:Data)
}
class FirebaseManager: NSObject {
// MARK: - Properties
var ref: FIRDatabaseReference!
var delegate:FirebaseManagerDelegate?
// MARK: - Initializers
override init() {
// Initialize the database reference
ref = FIRDatabase.database().reference()
super.init()
}
// MARK: - Places Functions
func getPlacesFromDatabase() {
// Create an array to store all the places
var allPlaces = [Place]()
// Before we retrieve from Firebase, check cachemanager
if let cachedPlacesDict = CacheManager.getPlacesFromCache() {
// We have data in cache, parse that instead
// Call function to parse places dictionary
allPlaces = parsePlacesFrom(placesDict: cachedPlacesDict)
// Now return the places array
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(places: allPlaces)
}
} // End DispatchQueue
return
}
// Retrieve the list of Places from the database
ref.child("places").observeSingleEvent(of: .value, with: { (snapshot) in
let placesDict = snapshot.value as? NSDictionary
// See if data is actually present
if let actualPlacesDict = placesDict {
// We actually have a places dictionary
// Before working with the data, save it into cache
CacheManager.putPlacesIntoCache(data: actualPlacesDict)
// Call function to parse places dictionary
allPlaces = self.parsePlacesFrom(placesDict: actualPlacesDict)
// Now return the places array
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(places: allPlaces)
}
} // End DispatchQueue
}
}) // End observeSingleEvent
} // End getForYouFromDatabase
// MARK: - Meta Functions
func getMetaFromDatabase(place:Place) {
// Before fetching from firebase, check cache
if let cachedMetaDict = CacheManager.getMetaFromCache(placeId: place.id) {
// Parse the meta data
parseMetaFrom(metaDict: cachedMetaDict, place: place)
// Notify the delegate the the meta data has been fetched
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(metaDataFor: place)
}
} // End DispatchQueue
return
}
ref.child("meta").child(place.id).observe(.value, with: { (snapshot) in
// Get the dictionary from the snapshot
if let metaDict = snapshot.value as? NSDictionary {
// Save data into cache
CacheManager.putMetaIntoCache(data: metaDict, placeId: place.id)
// Parse firebase results
self.parseMetaFrom(metaDict: metaDict, place: place)
// Notify the delegate the the meta data has been fetched
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(metaDataFor: place)
}
} // End DispatchQueue
}
}) // End observeSingleEvent
} // End getMetaFromDatabase
func getImageFromDatabase(imageName:String) {
// Get the image
// Check cache first
if let imageData = CacheManager.getImageFromCache(imageName: imageName) {
// Notify the delegate on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(imageName: imageName, imageData: imageData)
}
} // End DispatchQueue
return
}
// Create the storage and file path references
let storage = FIRStorage.storage()
let imagePathReference = storage.reference(withPath: imageName)
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
imagePathReference.data(withMaxSize: 1 * 1024 * 1024) { data, error in
if error != nil {
// Uh-oh, an error occurred!
} else if data != nil {
// Data for the image is returned
// Save the image data into cache
CacheManager.putImageIntoCache(data: data!, imageName: imageName)
// Notify the delegate on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(imageName: imageName, imageData: data!)
}
} // End DispatchQueue
}
}
}
func closeObserversForPlace(placeId:String) {
// Remove observers from that place node
ref.child("meta").child(placeId).removeAllObservers()
}
// MARK: - Version Functions
func getVersionFromDatabase() {
// Get the version from the database
ref.child("version").observeSingleEvent(of: .value, with: { (snapshot) in
let versionString = snapshot.value as? String
if let databaseVersion = versionString {
let cachedVersion = CacheManager.getVersionFromCache()
if cachedVersion != nil {
// Compare the cached version number to the database version
if databaseVersion > cachedVersion! {
// Remove all cached data
CacheManager.removeAllCachedData()
CacheManager.putVersionIntoCache(version: databaseVersion)
}
}
else {
// Save the database version number to cache
CacheManager.putVersionIntoCache(version: databaseVersion)
}
}
})
}
// MARK: - Helper Functions
func parsePlacesFrom(placesDict:NSDictionary) -> [Place] {
// Declare an array to store the parsed out places
var allPlaces = [Place]()
// Loop through all of the KVPs of the placesDict
for (placeid, placedata) in placesDict {
let placeDataDict = placedata as! NSDictionary
// Create a Place object for each and add it to an array to be returned
let place = Place()
place.id = placeid as! String
place.name = placeDataDict["name"] as! String
place.addr = placeDataDict["address"] as! String
place.lat = placeDataDict["lat"] as! Float
place.long = placeDataDict["long"] as! Float
place.type = PlaceType(rawValue: placeDataDict["type"] as! Int)!
place.cellImageName = placeDataDict["imagesmall"] as! String
place.createDate = placeDataDict["creationDate"] as! Int
// Put this place object into an array for returning
allPlaces += [place]
}
return allPlaces
}
func parseMetaFrom(metaDict:NSDictionary, place:Place) {
place.desc = metaDict["desc"] as! String
place.detailImageName = metaDict["imagebig"] as! String
}
} // End class
好的,这是您开始时需要了解的内容:
此方法 mapView(mapView: MKMapView, annotationView: MKAnnotationView, calloutAccessoryControlTapped control: UIControl)
通过您点击的 pin 调用,因此您需要从那里处理您的逻辑。
继续前进,当 MKAnnotationView
class 如此有限且其主要子项 (annotation
) 仅为您提供基础知识时,您将如何做到这一点:引脚 coordinates、title 和 subtitle... 简单,2 个选项:您可以自定义 class继承自它并在其中添加自定义参数,因此将能够包含您稍后将用于地图上每个图钉的相关信息 OR(我认为这可能是您选择的那个,因为它是 最简单的 并且更重要的是,它产生的冗余更少)您使用来自该点的坐标,然后根据所选点的坐标和您的坐标进行交叉匹配放置模型。这看起来很像以下几行:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
for p in places {
let testLocation = CLLocationCoordinate2D(latitude: CLLocationDegrees(p.lat), longitude: CLLocationDegrees(p.long))
if testLocation.latitude == view.annotation!.coordinate.latitude && testLocation.longitude == view.annotation!.coordinate.longitude {
performSegue(withIdentifier: "mapSegue", sender: p)
break
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedPlace = sender as! Place //Careful with these force unwrapping in the future, I'm just using it here for simplicity but you should always double check them
let detailModel = DetailModel()
detailModel.place = selectedPlace
let detailVC = segue.destination as! VenueDetailViewController
detailVC.model = detailModel
}
如您所见,您的 prepareForSegue 方法几乎保持不变,只是现在它利用了 sender 参数。在做 segue.destination as 时你也应该小心! VenueDetailViewController 因为,如果将来从此视图添加更多 segue,这可能会由于从其他 classes 发送的意外参数而导致崩溃。
我有一组要显示在 MapView 上的地点。我创建了一个 MKAnnotationView 来显示一个右键。然后我显示一个 detailView 并通过 segue 传递数据,但它显示错误的位置。我认为我的 selectedAnnotations 有问题。用户在任何时候只能 select 一个注释。
整个Class
import UIKit
import MapKit
class MapViewController: UIViewController, PlacesModelDelegate, CLLocationManagerDelegate {
@IBOutlet weak var mapView: MKMapView!
var places = [Place]()
var model:PlacesModel?
var locationManager:CLLocationManager?
var lastKnownLocation:CLLocation?
var selectedAnnotation: Place?
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
// Set map properties
mapView.showsUserLocation = true
// Instantiate location manager
locationManager = CLLocationManager()
locationManager?.delegate = self
// Instantiate places model if it is nil
if model == nil {
model = PlacesModel()
model?.delegate = self
}
// Call get places
model?.getPlaces()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Functions
func plotPins() {
var pinsArray = [MKPointAnnotation]()
// Go through the array of places and plot them
for p in places {
// Create a pin
let pin = MKPointAnnotation()
// Set its properties
pin.coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(p.lat), longitude: CLLocationDegrees(p.long))
pin.title = p.name
pin.subtitle = p.getTypeName()
// Add it to the map
mapView.addAnnotation(pin)
// Store the pin in the pinsArray
pinsArray.append(pin)
}
// Center the map
mapView.showAnnotations(pinsArray, animated: true)
}
func displaySettingsPopup() {
// Create alert controller
let alertController = UIAlertController(title: "Couldn't find your location",
message: "Location Services is turned off on your device or the GuideBookApp doesn't have permission to find your location. Please check your Privacy settings to continue.",
preferredStyle: .alert)
// Create settings button action
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (alertAction) in
if let appSettings = URL(string: UIApplicationOpenSettingsURLString) {
UIApplication.shared.open(appSettings, options: [:], completionHandler: nil)
}
}
alertController.addAction(settingsAction)
// Create cancel button action
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
// Show the alert
present(alertController, animated: true, completion: nil)
}
// MARK: - Button Handlers
@IBAction func locationButtonTapped(_ sender: UIButton) {
// Check if location services are enabled
if CLLocationManager.locationServicesEnabled() {
// They're enabled, now check the authorization status
let status = CLLocationManager.authorizationStatus()
if status == .authorizedAlways || status == .authorizedWhenInUse {
// Has permission
locationManager?.startUpdatingLocation()
// Center the map on last location
if let actualLocation = lastKnownLocation {
mapView.setCenter(actualLocation.coordinate, animated: true)
}
}
else if status == .denied || status == .restricted {
// Doesn't have permission
// Tell user to check settings
displaySettingsPopup()
}
else if status == .notDetermined {
// Ask the user for permission
locationManager?.requestWhenInUseAuthorization()
}
}
else {
// Locations services are turned off
// Tell user to check settings
displaySettingsPopup()
}
}
// MARK: - PlacesModelDelegate Methods
func placesModel(places: [Place]) {
// Set places property
self.places = places
// Plot the pins
plotPins()
}
// MARK: - CLLocationManagerDelegate Methods
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
if let actualLocation = location {
// Create a pin
let pin = MKPointAnnotation()
pin.coordinate = CLLocationCoordinate2D(latitude: actualLocation.coordinate.latitude, longitude: actualLocation.coordinate.longitude)
// Center the map, only if it's the first time locating the user
if lastKnownLocation == nil {
mapView.setCenter(actualLocation.coordinate, animated: true)
}
// Save the pin
lastKnownLocation = actualLocation
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// See what the user has answered
if status == .denied {
// Tell user that this app doesn't have permission. They can change it in their settings
displaySettingsPopup()
}
else if status == .authorizedWhenInUse || status == .authorizedAlways {
// Permission granted
locationManager?.startUpdatingLocation()
}
}
}
extension MapViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "marker"
var view: MKMarkerAnnotationView
view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
return view
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
performSegue(withIdentifier: "mapSegue", sender: view)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedRow = mapView.selectedAnnotations.endIndex
let selectedPlace = places[selectedRow]
let detailModel = DetailModel()
detailModel.place = selectedPlace
let detailVC = segue.destination as! VenueDetailViewController
detailVC.model = detailModel
}
}
放置模型
import UIKit
protocol PlacesModelDelegate {
func placesModel(places:[Place])
}
class PlacesModel: NSObject, FirebaseManagerDelegate {
// Properties
var delegate:PlacesModelDelegate?
var firManager:FirebaseManager?
func getPlaces() {
// Get places from FirebaseManager
if firManager == nil {
firManager = FirebaseManager()
firManager!.delegate = self
}
// Tell firebase manager to fetch places
firManager!.getPlacesFromDatabase()
}
func checkDataVersion() {
// Get version from FirebaseManager
if firManager == nil {
firManager = FirebaseManager()
firManager!.delegate = self
}
firManager!.getVersionFromDatabase()
}
// MARK: - FirebaseManager Delegate Methods
func firebaseManager(places: [Place]) {
// Notify the delegate
if let actualDelegate = delegate {
actualDelegate.placesModel(places: places)
}
}
}
FirebaseManager
import UIKit
import Firebase
@objc protocol FirebaseManagerDelegate {
@objc optional func firebaseManager(places:[Place])
@objc optional func firebaseManager(metaDataFor place:Place)
@objc optional func firebaseManager(imageName:String, imageData:Data)
}
class FirebaseManager: NSObject {
// MARK: - Properties
var ref: FIRDatabaseReference!
var delegate:FirebaseManagerDelegate?
// MARK: - Initializers
override init() {
// Initialize the database reference
ref = FIRDatabase.database().reference()
super.init()
}
// MARK: - Places Functions
func getPlacesFromDatabase() {
// Create an array to store all the places
var allPlaces = [Place]()
// Before we retrieve from Firebase, check cachemanager
if let cachedPlacesDict = CacheManager.getPlacesFromCache() {
// We have data in cache, parse that instead
// Call function to parse places dictionary
allPlaces = parsePlacesFrom(placesDict: cachedPlacesDict)
// Now return the places array
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(places: allPlaces)
}
} // End DispatchQueue
return
}
// Retrieve the list of Places from the database
ref.child("places").observeSingleEvent(of: .value, with: { (snapshot) in
let placesDict = snapshot.value as? NSDictionary
// See if data is actually present
if let actualPlacesDict = placesDict {
// We actually have a places dictionary
// Before working with the data, save it into cache
CacheManager.putPlacesIntoCache(data: actualPlacesDict)
// Call function to parse places dictionary
allPlaces = self.parsePlacesFrom(placesDict: actualPlacesDict)
// Now return the places array
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(places: allPlaces)
}
} // End DispatchQueue
}
}) // End observeSingleEvent
} // End getForYouFromDatabase
// MARK: - Meta Functions
func getMetaFromDatabase(place:Place) {
// Before fetching from firebase, check cache
if let cachedMetaDict = CacheManager.getMetaFromCache(placeId: place.id) {
// Parse the meta data
parseMetaFrom(metaDict: cachedMetaDict, place: place)
// Notify the delegate the the meta data has been fetched
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(metaDataFor: place)
}
} // End DispatchQueue
return
}
ref.child("meta").child(place.id).observe(.value, with: { (snapshot) in
// Get the dictionary from the snapshot
if let metaDict = snapshot.value as? NSDictionary {
// Save data into cache
CacheManager.putMetaIntoCache(data: metaDict, placeId: place.id)
// Parse firebase results
self.parseMetaFrom(metaDict: metaDict, place: place)
// Notify the delegate the the meta data has been fetched
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(metaDataFor: place)
}
} // End DispatchQueue
}
}) // End observeSingleEvent
} // End getMetaFromDatabase
func getImageFromDatabase(imageName:String) {
// Get the image
// Check cache first
if let imageData = CacheManager.getImageFromCache(imageName: imageName) {
// Notify the delegate on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(imageName: imageName, imageData: imageData)
}
} // End DispatchQueue
return
}
// Create the storage and file path references
let storage = FIRStorage.storage()
let imagePathReference = storage.reference(withPath: imageName)
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
imagePathReference.data(withMaxSize: 1 * 1024 * 1024) { data, error in
if error != nil {
// Uh-oh, an error occurred!
} else if data != nil {
// Data for the image is returned
// Save the image data into cache
CacheManager.putImageIntoCache(data: data!, imageName: imageName)
// Notify the delegate on the main thread
DispatchQueue.main.async {
// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(imageName: imageName, imageData: data!)
}
} // End DispatchQueue
}
}
}
func closeObserversForPlace(placeId:String) {
// Remove observers from that place node
ref.child("meta").child(placeId).removeAllObservers()
}
// MARK: - Version Functions
func getVersionFromDatabase() {
// Get the version from the database
ref.child("version").observeSingleEvent(of: .value, with: { (snapshot) in
let versionString = snapshot.value as? String
if let databaseVersion = versionString {
let cachedVersion = CacheManager.getVersionFromCache()
if cachedVersion != nil {
// Compare the cached version number to the database version
if databaseVersion > cachedVersion! {
// Remove all cached data
CacheManager.removeAllCachedData()
CacheManager.putVersionIntoCache(version: databaseVersion)
}
}
else {
// Save the database version number to cache
CacheManager.putVersionIntoCache(version: databaseVersion)
}
}
})
}
// MARK: - Helper Functions
func parsePlacesFrom(placesDict:NSDictionary) -> [Place] {
// Declare an array to store the parsed out places
var allPlaces = [Place]()
// Loop through all of the KVPs of the placesDict
for (placeid, placedata) in placesDict {
let placeDataDict = placedata as! NSDictionary
// Create a Place object for each and add it to an array to be returned
let place = Place()
place.id = placeid as! String
place.name = placeDataDict["name"] as! String
place.addr = placeDataDict["address"] as! String
place.lat = placeDataDict["lat"] as! Float
place.long = placeDataDict["long"] as! Float
place.type = PlaceType(rawValue: placeDataDict["type"] as! Int)!
place.cellImageName = placeDataDict["imagesmall"] as! String
place.createDate = placeDataDict["creationDate"] as! Int
// Put this place object into an array for returning
allPlaces += [place]
}
return allPlaces
}
func parseMetaFrom(metaDict:NSDictionary, place:Place) {
place.desc = metaDict["desc"] as! String
place.detailImageName = metaDict["imagebig"] as! String
}
} // End class
好的,这是您开始时需要了解的内容:
此方法 mapView(mapView: MKMapView, annotationView: MKAnnotationView, calloutAccessoryControlTapped control: UIControl)
通过您点击的 pin 调用,因此您需要从那里处理您的逻辑。
继续前进,当 MKAnnotationView
class 如此有限且其主要子项 (annotation
) 仅为您提供基础知识时,您将如何做到这一点:引脚 coordinates、title 和 subtitle... 简单,2 个选项:您可以自定义 class继承自它并在其中添加自定义参数,因此将能够包含您稍后将用于地图上每个图钉的相关信息 OR(我认为这可能是您选择的那个,因为它是 最简单的 并且更重要的是,它产生的冗余更少)您使用来自该点的坐标,然后根据所选点的坐标和您的坐标进行交叉匹配放置模型。这看起来很像以下几行:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
for p in places {
let testLocation = CLLocationCoordinate2D(latitude: CLLocationDegrees(p.lat), longitude: CLLocationDegrees(p.long))
if testLocation.latitude == view.annotation!.coordinate.latitude && testLocation.longitude == view.annotation!.coordinate.longitude {
performSegue(withIdentifier: "mapSegue", sender: p)
break
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedPlace = sender as! Place //Careful with these force unwrapping in the future, I'm just using it here for simplicity but you should always double check them
let detailModel = DetailModel()
detailModel.place = selectedPlace
let detailVC = segue.destination as! VenueDetailViewController
detailVC.model = detailModel
}
如您所见,您的 prepareForSegue 方法几乎保持不变,只是现在它利用了 sender 参数。在做 segue.destination as 时你也应该小心! VenueDetailViewController 因为,如果将来从此视图添加更多 segue,这可能会由于从其他 classes 发送的意外参数而导致崩溃。