Strange behaviour in showing annotations images on map using data coming from Firebase. SWIFT 4.1 - ios

The strange behaviour is that when I add a new annotation, either tapped or user location, it gets displayed with the right chosen icon. When MapVC load for the first time, the posts retrieved from Firebase have all the same icon, ( the icon name of the latest one posted. If, after posting a new one, I exit mapViewVc to the menuVC and re enter mapViewVC than every icon is displaying the same icon again, now being my previously posted one.
a Few times it happened the the icons were two different icons, randomly chosen.
I don't understand why the coordinates are taken right but the image is not.
The app flow is:
I have a mapView vc where I can either double tap on screen and get coordinate or code user location coordinate via a button and then get to an chooseIconVc where I have all available icons to choose for the annotation. Once I select one, the icon name get passed back in in mapViewVC in unwindHere() that stores icon name into a variable and coordinates into another. In postAlertNotification those variables get posted to Firebase.
In displayAlerts() the data from Firebase gets stored into variables to initialise an annotation and gets added to mapView.
chosen icon:
#IBAction func unwindHere(sender:UIStoryboardSegue) { // data coming back
if let sourceViewController = sender.source as? IconsViewController {
alertNotificationType = sourceViewController.dataPassed
if tapCounter > 0 {
alertNotificationLatitude = String(describing: alertCoordinates.latitude)
alertNotificationLongitude = String(describing: alertCoordinates.longitude)
postAlertNotification() // post new notification to Firebase
} else {
alertCoordinates = self.trackingCoordinates
alertNotificationLatitude = String(describing: self.trackingCoordinates!.latitude)
alertNotificationLongitude = String(describing: self.trackingCoordinates!.longitude)
postAlertNotification() // post new notification to Firebase
}
}
}
than post:
func postAlertNotification() {
// to set next notification id as the position it will have in array ( because first position is 0 ) we use the array.count as value
let latitude = alertNotificationLatitude
let longitude = alertNotificationLongitude
let alertType = alertNotificationType
let post: [String:String] = [//"Date" : date as! String,
//"Time" : time as! String,
"Latitude" : latitude as! String,
"Longitude" : longitude as! String,
"Description" : alertType as! String]
var ref: DatabaseReference!
ref = Database.database().reference()
ref.child("Community").child("Alert Notifications").childByAutoId().setValue(post)
}
retrieve and display:
func displayAlerts() {
ref = Database.database().reference()
databaseHandle = ref?.child("Community").child("Alert Notifications").observe(.childAdded, with: { (snapshot) in
// defer { self.dummyFunctionToFoolFirebaseObservers() }
guard let data = snapshot.value as? [String:String] else { return }
guard let firebaseKey = snapshot.key as? String else { return }
// let date = data!["Date"]
// let time = data!["Time"]
let dataLatitude = data["Latitude"]!
let dataLongitude = data["Longitude"]!
self.alertIconToDisplay = data["Description"]!
let doubledLatitude = Double(dataLatitude)
let doubledLongitude = Double(dataLongitude)
let recombinedCoordinate = CLLocationCoordinate2D(latitude: doubledLatitude!, longitude: doubledLongitude!)
print("Firebase post retrieved !")
print("Longitude Actual DataKey is \(String(describing: firebaseKey))")
print("fir long \((snapshot.value!, snapshot.key))")
self.userAlertAnnotation = UserAlert(type: self.alertIconToDisplay!, coordinate: recombinedCoordinate, firebaseKey: firebaseKey)
self.mapView.addAnnotation(self.userAlertAnnotation)
})
}
and
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: userAlertAnnotation, reuseIdentifier: "") // CHANGE FOR NEW ANNOTATION : FULL DATA
//added if statement for displaying user location blue dot
if annotation is MKUserLocation{
return nil
} else {
annotationView.image = UIImage(named: alertIconToDisplay!) // choose the image to load
let transform = CGAffineTransform(scaleX: 0.27, y: 0.27)
annotationView.transform = transform
return annotationView
}
}
the variables declarations :
var alertIconToDisplay: String?
var userAlertAnnotation: UserAlert!
var alertNotificationType: String?
var alertNotificationLatitude: String?
var alertNotificationLongitude: String?
UPDATE:
annotation cLass:
import MapKit
class UserAlert: NSObject , MKAnnotation {
var type: String?
var firebaseKey: String?
var coordinate = CLLocationCoordinate2D()
var image: UIImage?
override init() {
}
init(type:String, coordinate:CLLocationCoordinate2D, firebaseKey: String) {
self.type = type
self.firebaseKey = firebaseKey
self.coordinate = coordinate
}
}

After understanding where the problem I was explained how to changed the displayAlert() into
func displayAlerts() { // rajish version
ref = Database.database().reference()
databaseHandle = ref?.child("Community").child("Alert Notifications").observe(.childAdded, with: { (snapshot) in
// defer { self.dummyFunctionToFoolFirebaseObservers() }
guard let data = snapshot.value as? [String:String] else { return }
guard let firebaseKey = snapshot.key as? String else { return }
// let date = data!["Date"]
// let time = data!["Time"]
let dataLatitude = data["Latitude"]!
let dataLongitude = data["Longitude"]!
let type = data["Description"]!
let id = Int(data["Id"]!)
let doubledLatitude = Double(dataLatitude)
let doubledLongitude = Double(dataLongitude)
let recombinedCoordinate = CLLocationCoordinate2D(latitude: doubledLatitude!, longitude: doubledLongitude!)
print("Firebase post retrieved !")
print("Longitude Actual DataKey is \(String(describing: firebaseKey))")
print("fir long \((snapshot.value!, snapshot.key))")
var userAlertAnnotation = UserAlert(type: type, coordinate: recombinedCoordinate, firebaseKey: firebaseKey, title: type,id: id!)
self.userAlertNotificationArray.append(userAlertAnnotation) // array of notifications coming from Firebase
print("user alert array after append from Firebase is : \(self.userAlertNotificationArray)")
self.alertNotificationArray.append(recombinedCoordinate) // array for checkig alerts on route
self.mapView.addAnnotation(userAlertAnnotation)
})
}
and the mapView to:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { // rajish version
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "")
if annotation is MKUserLocation{
return nil
} else {
print(annotation.coordinate)
annotationView.image = UIImage(named:(annotationView.annotation?.title)! ?? "")
// annotationView.canShowCallout = true
let transform = CGAffineTransform(scaleX: 0.27, y: 0.27)
annotationView.transform = transform
return annotationView
}
}
that solved it.

Related

Xcode and Swift: Colors and Object ID not being applied to map markers?

I'm making a test app that is taking in geological points of interest from a JSON file and plotting the points on a map (you can see the info I am getting here: https://maine.hub.arcgis.com/datasets/ff3e487fb782464684f8c1f8a1b7e58d_0/about and you can see the JSON file there as well). I've been trying to color-code the points to correspond to the category of geological feature (bedrock is red, coastal is green, surficial is purple, etc.). However, when I try to apply the colors, it doesn't work. The app runs just fine, and I can see all the points, they're just not color-coded or labeled as their object ID.
This is the file I used for each item (titled Artwork because this project was previously locations of artworks in Oahu, but changed to geological formations in Maine):
import Foundation
import MapKit
import Contacts
import SwiftUI
class Artwork: NSObject, MKAnnotation {
let title: String?
let locationName: String?
let type: String?
let coordinate: CLLocationCoordinate2D
let objectID: Int?
init(title: String?, locationName: String?, type: String?, coordinate: CLLocationCoordinate2D, objectID: Int?) {
self.title = title
self.locationName = locationName
self.type = type
self.coordinate = coordinate
self.objectID = objectID
super.init()
}
init?(feature: MKGeoJSONFeature) {
guard
let point = feature.geometry.first as? MKPointAnnotation,
let propertiesData = feature.properties,
let json = try? JSONSerialization.jsonObject(with: propertiesData),
let properties = json as? [String: Any]
else {
return nil
}
title = properties["SITE_NAME"] as? String
locationName = properties["TOWN"] as? String
type = properties["CATEGORY"] as? String
coordinate = point.coordinate
objectID = properties["OBJECTID"] as? Int
super.init()
}
var subtitle: String? {
return locationName
}
var mapItem: MKMapItem? {
guard let location = locationName else {
return nil
}
let addressDict = [CNPostalAddressStreetKey: location]
let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: addressDict)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = title
return mapItem
}
//This is where I code the method for choosing the color
var markerTintColor: UIColor {
switch type {
case "Bedrock":
return .red
case "Coastal":
return .green
case "Surficial":
return .purple
case "Bedrock, Surficial":
return .blue
case "Bedrock, Surficial, Coastal":
return .cyan
case "Surficial, Coastal":
return .magenta
case "Bedrock, Coastal":
return .orange
default:
return .gray
}
}
}
Here is another file that might be important, ArtworkViews.swift:
import Foundation
import MapKit
import SwiftUI
class ArtworkViews: MKMarkerAnnotationView {
override var annotation: MKAnnotation? {
willSet {
guard let artwork = newValue as? Artwork else {
return
}
canShowCallout = true
calloutOffset = CGPoint(x: -5, y: 5)
rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
//This is where the color and ID are applied
markerTintColor = artwork.markerTintColor
if let ID = artwork.objectID {
glyphText = String(ID)
}
}
}
}
And here is where I implement the colors in ViewController.swift (this the viewDidLoad() function):
let initialLocation = CLLocation(latitude: 44.883427, longitude: -68.670815)
mapView.centerToLocation(initialLocation)
let maineCenter = CLLocation(latitude: 44.883427, longitude: -68.670815)
let region = MKCoordinateRegion(center: maineCenter.coordinate, latitudinalMeters: 600000, longitudinalMeters: 300000)
mapView.setCameraBoundary(MKMapView.CameraBoundary(coordinateRegion: region), animated: true)
let zoomRange = MKMapView.CameraZoomRange(maxCenterCoordinateDistance: 1400000)
mapView.setCameraZoomRange(zoomRange, animated: true)
mapView.delegate = self
//This is where the color is ultimately applied
mapView.register(ArtworkViews.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
loadInitialData()
mapView.addAnnotations(artworks)

UIlabel() tap to expand text

So I am building a map that provides factual data on a variety of points located in Washington DC. The data is getting pulled from a geojson and listed as 20 or so points. When you click on the point, there is a popup that occurs that shows a truncated version of the text, only 10 lines. However some of the text is really long, 200 lines+. I want to develop a way to expand the text, or have a scrollable bar. Basically anything to have the option to open up the text. Adding an image to show what it looks like.
You can see an image here: https://i.stack.imgur.com/yeeBa.jpg
Here is the code I am using.
The data is getting called in the ViewController.swift using this
func loadInitialData() {
// 1
guard let fileName = Bundle.main.path(forResource: "PublicArt4", ofType: "json")
else { return }
let optionalData = try? Data(contentsOf: URL(fileURLWithPath: fileName))
guard
let data = optionalData,
// 2
let json = try? JSONSerialization.jsonObject(with: data),
// 3
let dictionary = json as? [String: Any],
// 4
let works = dictionary["data"] as? [[Any]]
else { return }
// 5
let validWorks = works.compactMap { Artwork(json: $0) }
artworks.append(contentsOf: validWorks)
}
}
The artworkViews.swift displays the label formatting
let detailLabel = UILabel()
detailLabel.text = artwork.locationlink
detailLabel.text = artwork.subtitle
detailCalloutAccessoryView = detailLabel
detailLabel.font = UIFont(name: "Heiti TC", size: 12)
detailLabel.numberOfLines = 10
//detailLabel.adjustsFontSizeToFitWidth = true
// detailLabel.minimumScaleFactor = 0.5
// detailLabel.baselineAdjustment = .alignCenters
// detailLabel.textAlignment = .left
The geojson is formatted like this
{"data" : [ [
1,
"Washington Monument",
"Click here to learn more",
"Madison Dr NW & 15th St NW",
"Washington",
"DC",
20001,
"38.89013",
"-77.033031",
"www.google.com Welcome to the Washington Monument,",
"Mural",
"Some text, not sure what it is",
" "
],...
The Artwork.swift pulls the data in such a way
class Artwork: NSObject, MKAnnotation {
let title: String?
let locationName: String
let locationURL: String
let discipline: String
let coordinate: CLLocationCoordinate2D
init(title: String, locationName: String, locationURL: String, discipline: String, coordinate: CLLocationCoordinate2D) {
self.title = title
self.locationName = locationName
self.locationURL = locationURL
self.discipline = discipline
self.coordinate = coordinate
super.init()
}
var subtitle: String? {
return locationName
}
var locationlink: String? {
return locationURL
}
init?(json: [Any]) {
// 1
if let title = json[2] as? String {
self.title = title
} else {
self.title = "No Title"
}
// json[11] is the long description
//self.locationName = json[11] as! String
// json[12] is the short location string
self.locationName = json[9] as! String
self.discipline = json[10] as! String
self.locationURL = json[3] as! String
// 2
if let latitude = Double(json[7] as! String),
let longitude = Double(json[8] as! String) {
self.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
} else {
self.coordinate = CLLocationCoordinate2D()
}
}
// pinTintColor for disciplines: Sculpture, Plaque, Mural, Monument, other
var markerTintColor: UIColor {
switch discipline {
case "Monument":
return .red
case "Mural":
return .cyan
case "Plaque":
return .blue
case "Sculpture":
return .purple
default:
return .green
}
}
var imageName: String? {
if discipline == "Mural" { return "Flag" }
return "Flag"
}
// Annotation right callout accessory opens this mapItem in Maps app
func mapItem() -> MKMapItem {
let addressDict = [CNPostalAddressStreetKey: subtitle!]
let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: addressDict)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = title
return mapItem
}
}
The one thing I tried was to switch it to a UITextView, but i cant get that to load properly. Mainly because I am not sure how to integrate it into the ViewController.
let detailLabel = UITextView()
detailLabel.text = artwork.locationlink
detailLabel.text = artwork.subtitle
detailLabel.textColor = UIColor.red
detailLabel.selectedTextRange = detailLabel.textRange(from: detailLabel.beginningOfDocument, to: detailLabel.beginningOfDocument)
```

Find selected MapKit Annotation's postID

I'm trying to set the selected MapKit's Annotation ID (mapEventID in my case) on didSelect and to use when Swift is preparing the segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let postViewVC = segue.destination as! PostView
postViewVC.eventID = mapEventID
}
mapEventID is initialized in the GeoFire observer:
func retrieveAllEvents () {
let postDB = Database.database().reference().child("DBName")
postDB.observe(.childAdded) { (snapshot) in
let snapshotValue = snapshot.value as! Dictionary <String,AnyObject>
let postTitle = snapshotValue ["EventTitle"]!
let postLocation = snapshotValue ["VisibleLocation"]!
let eventID = snapshotValue ["EventID"]
let postTime = snapshotValue ["EventDateTimeStart"]!
let date = self.convertTimestamp(serverTimestamp: postTime as! Double)
let mapEventDetails : String = "\(date) - \(postLocation)"
self.geoFire.getLocationForKey(locationID! as! String) { (location, error) in
if (error != nil) {
print("An error occurred getting the location for eventID:", eventID as Any)
} else if (location != nil) {
let postLat = location?.coordinate.latitude
let postLong = location?.coordinate.longitude
let coordinate = CLLocationCoordinate2D(latitude: postLat!, longitude: postLong!)
let annotation = EventAnnotation (coordinate: coordinate, withKey: eventID as! String, title: mapEventDetails, subtitle: mapEventDetails)
self.mapEventID = annotation.eventKey
self.eventMap.addAnnotation(annotation)
} else {
print("GeoFire does not contain a location for:", eventID as Any)
}
}
}
}
The problem is that it always uses the most recently added post's ID as the mapEventID and not the one the user actually tapped on. This makes sense because when the IDs are retrieved from Firebase through the observer it 'observes' for all the keys and the most recent one becomes the ID.
How do I obtain the specific mapEventID when the user taps on the annotation? At the moment I have:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
mapEventID = //How do I change the EventID here?
}
I was hoping I could add the ID to the annotation's Description' property in the Geofire observer but Swift does not provide any syntax for that in:
let annotation = EventAnnotation (coordinate: coordinate, withKey: eventID as! String, title: postTitle, subtitle: eventDetails)
Try the following code:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if let annotation = view.annotation as? EventAnnotation {
mapEventID = annotation.eventKey
}
}

SWIFT 4.1 Cannot invoke initializer for type 'Double' with an argument list of type '(String?)'

I'm retrieving mapView annotations posted in Firebase to show them on map, but while converting String values for latitude and longitude to recombine them into CLLocationCoordinates2D I get the error. I don't understand why, because in another function I use the same method but getting the values from arrays but I don't get the error. Also on retrieving the data I would like to also use the key value from firebase as initialiser for my annotations. But I get two more errors Use of unresolved identifier 'firebaseKey' and Use of unresolved identifier 'recombinedCoordinate' for initialisers. Here're the function:
func displayAlerts() {
// FIREBASE: Reference
ref = Database.database().reference()
// FIREBASE:Retrieve posts and listen for changes
databaseHandle = ref?.child("Community").child("Alert Notifications").observe(.childAdded, with: { (snapshot) in
let data = snapshot.value as? [String:String]
if let actualData = data {
let dataLatitude = data!["Latitude"]
let dataLongitude = data!["Longitude"]
self.alertIconToDisplay = data!["Description"]
let doubledLatitude = Double(dataLatitude)
let doubledLongitude = Double(dataLongitude)
var recombinedCoordinate = CLLocationCoordinate2D(latitude: doubledLatitude!, longitude: doubledLongitude!)
print("Firebase post retrieved !")
self.dummyFunctionToFoolFirebaseObservers()
}
let dataKey = snapshot.key as? String
if let firebaseKey = dataKey {
print("Longitude DataKey is \(String(describing: dataKey))")
print("Longitude Actual DataKey is \(String(describing: firebaseKey))")
self.dummyFunctionToFoolFirebaseObservers()
}
print("fir long \((snapshot.value!, snapshot.key))")
userAlertAnnotation = UserAlert(type: self.alertIconToDisplay, coordinate: recombinedCoordinate, firebaseKey: firebaseKey)
self.mapView.addAnnotation(self.userAlertAnnotation)
})
}
Here's the annotation model :
class UserAlert: NSObject , MKAnnotation {
var type: String?
var firebaseKey: String?
var coordinate:CLLocationCoordinate2D
init(type:String, coordinate:CLLocationCoordinate2D, firebaseKey: String) {
self.type = type
self.firebaseKey = firebaseKey
self.coordinate = coordinate
}
}
What am I doing wrong here? I understand that the error on the initialisers are because initialisation occurs in key closures, but how then I incorporate all data into initialiser ?
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: userAlertAnnotation, reuseIdentifier: "") // CHANGE FOR NEW ANNOTATION : FULL DATA
//added if statement for displaying user location blue dot
if annotation is MKUserLocation{
return nil
} else {
annotationView.image = UIImage(named: alertIconToDisplay!) // choose the image to load
let transform = CGAffineTransform(scaleX: 0.27, y: 0.27)
annotationView.transform = transform
return annotationView
}
}
func postAlertNotification() {
// to set next notification id as the position it will have in array ( because first position is 0 ) we use the array.count as value
let latitude = alertNotificationLatitude
let longitude = alertNotificationLongitude
let alertType = alertNotificationType
let post: [String:String] = [//"Date" : date as! String,
//"Time" : time as! String,
"Latitude" : latitude as! String,
"Longitude" : longitude as! String,
"Description" : alertType as! String]
var ref: DatabaseReference!
ref = Database.database().reference()
ref.child("Community").child("Alert Notifications").childByAutoId().setValue(post)
}
The error in the topic says that you can't create a Double from an optional String which is true.
To solve it force unwrap the values for Latitude and Longitude.
But the main issue is a scope issue, all variables used in the initializer must be in the same scope. You can flatten the scope with guard statements:
...
databaseHandle = ref?.child("Community").child("Alert Notifications").observe(.childAdded, with: { (snapshot) in
defer { self.dummyFunctionToFoolFirebaseObservers() }
guard let data = snapshot.value as? [String:String] else { return }
guard let firebaseKey = snapshot.key as? String else { return }
// let date = data!["Date"]
// let time = data!["Time"]
let dataLatitude = data["Latitude"]!
let dataLongitude = data["Longitude"]!
self.alertIconToDisplay = data["Description"]!
let doubledLatitude = Double(dataLatitude)
let doubledLongitude = Double(dataLongitude)
let recombinedCoordinate = CLLocationCoordinate2D(latitude: doubledLatitude!, longitude: doubledLongitude!)
print("Firebase post retrieved !")
// self .keyaLon = dataKey
// self.keyaLonArray.append(firebaseKey)
print("Longitude Actual DataKey is \(String(describing: firebaseKey))")
print("fir long \((snapshot.value!, snapshot.key))")
self.userAlertAnnotation = UserAlert(type: self.alertIconToDisplay, coordinate: recombinedCoordinate, firebaseKey: firebaseKey)
self.mapView.addAnnotation(self.userAlertAnnotation)
})

Core Data Error when segueing: Failed to call designated initializer on NSManagedObject class

I have a view controller that segues to another view controller when a pin on the mapView is tapped. "Pin" is an NSManagedObject that gets populated with latitude and longitude before being sent to the second view controller (where a function populates it with actual images).
I am getting the error "CoreData: error: Failed to call designated initializer on NSManagedObject class 'Pin'" after my didSelect function is completed and before my performSegue function is called.
#nonobjc public class func fetchRequest() -> NSFetchRequest<Pin> {
return NSFetchRequest<Pin>(entityName: "Pin")
}
#NSManaged public var latitude: Double
#NSManaged public var longitude: Double
#NSManaged public var images: NSSet?
This is the class:
convenience init(latitude: Double, longitude: Double, context: NSManagedObjectContext) {
if let entity = NSEntityDescription.entity(forEntityName: "Pin", in: context) {
self.init(entity: entity, insertInto: context)
self.latitude = latitude
self.longitude = longitude
} else {
fatalError("Unable to find entity name")
}
}
I have tried declaring pin as an optional and force declaring it with "!". None of these two options works. Based on what I've learned and read on many posts online I will need to initialize the pin variable using the designated initializer. This is my attempt at the top of the view controller class, but it's not working either.
var pin = Pin.init(entity: NSEntityDescription.entity(forEntityName: "Pin", in: CoreDataStack.sharedInstance().context)!, insertInto: CoreDataStack.sharedInstance().context)
Creating the pin:
// Create the annotation
let touchPoint = gestureRecognizer.location(in: mapView)
let newCoordinate = self.mapView.convert(touchPoint, toCoordinateFrom:self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinate
pin = Pin(latitude: annotation.coordinate.latitude, longitude: annotation.coordinate.longitude, context: CoreDataStack.sharedInstance().context)
let pinAnnotation = PinAnnotation(objectID: pin.objectID, title: nil, subtitle: nil, coordinate: annotation.coordinate)
// Add the annotation
mapView.addAnnotation(pinAnnotation)
CoreDataStack.sharedInstance().saveContext()
Selecting the pin in didSelect:
do {
let pinAnnotation = view.annotation as! PinAnnotation
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Pin")
let predicate = NSPredicate(format: "latitude == %# AND longitude == %#", argumentArray: [pinAnnotation.coordinate.latitude, pinAnnotation.coordinate.longitude])
fetchRequest.predicate = predicate
let pins = try CoreDataStack.sharedInstance().context.fetch(fetchRequest) as? [Pin]
pin = pins![0]
} catch let error as NSError {
print("failed to get pin by object id")
print(error.localizedDescription)
return
}
self.performSegue(withIdentifier: "collectionViewSegue", sender: self)
...and performing the segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "collectionViewSegue" {
let controller = segue.destination as! CollectionViewController
print("CoreDataStack context in segue= \(CoreDataStack.sharedInstance().context)")
controller.selectedPin = pin
if let images = pin.images?.allObjects as? [Images] {
controller.photos = images
}
print("PrepareForSegue pin properties are: \n latitude: \(pin.latitude) \n longitude: \(pin.longitude)")
}
}
What am I missing?
I resolved this by making my variable declaration optional in the beginning of my class:
var selectedPin: Pin?
...and initializing differently within my long press gestureRecognizer function:
#objc func handleLongPress(_ gestureRecognizer : UIGestureRecognizer) {
if gestureRecognizer.state != .began { return }
print("Tap gesture recognized")
// Create the annotation
let touchPoint = gestureRecognizer.location(in: mapView)
let newCoordinate = self.mapView.convert(touchPoint, toCoordinateFrom:self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinate
// Initialize NSManagedObject 'Pin' with properties
selectedPin = Pin(context: CoreDataStack.sharedInstance().context)
selectedPin?.latitude = annotation.coordinate.latitude
selectedPin?.longitude = annotation.coordinate.longitude
if let selectedPin = selectedPin {
let pinAnnotation = PinAnnotation(objectID: selectedPin.objectID, title: nil, subtitle: nil, coordinate: annotation.coordinate)
// Add the annotation
mapView.addAnnotation(pinAnnotation)
}
CoreDataStack.sharedInstance().saveContext()
print("This is what the ole save looks like: \(CoreDataStack.sharedInstance().context)")
}

Resources