Search code examples
swiftparse-platformmkpointannotation

MKPointAnnotation and PFObject


Summary: Linking (NOT Query) Annotation with Parse from app

Completed: What I'm trying to do is have the newly created annotation, become a PFObject as a result. The way I am attempting to do this is to get the coordinates based off of the MKPointAnnotation. Then turn that into a PFObject with coordinates. Then able to be Query later as a live update.

Problem Still an issue is that with the code mentioned I'm not able to have the MKPointAnnotation which allows for me to add the title and UIImage, other than that all I would need tips on would be combining all of that together to finally be able to be queried from parse.

func handleLongPress(getstureRecognizer : UIGestureRecognizer) {
    if getstureRecognizer.state != .Began { return }

    let touchPoint = getstureRecognizer.locationInView(self.mapView)
    let touchMapCoordinate = mapView.convertPoint(touchPoint, toCoordinateFromView: mapView)
    createAnnotation(touchMapCoordinate)

}

private func createAnnotation(coordinate: CLLocationCoordinate2D) {
    print("createAnnotation")
    let myAnnotation = MyAnnotation(coordinate: coordinate)
    mapView.addAnnotation(myAnnotation)
    myAnnotation.saveInBackground()


}

    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
        if !(annotation is MKPointAnnotation) {
    return nil
}

let reuseId = "test"

var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if pinView == nil {
    pinView = MyAnnotation(annotation: annotation, reuseIdentifier: reuseId)
    pinView!.image = UIImage(named:"Cloud9")
    pinView!.canShowCallout = true

    let rightButton: AnyObject! = UIButton(type: UIButtonType.ContactAdd)
    pinView?.rightCalloutAccessoryView = rightButton as? UIView

Solution

  • It is not quite clear to me what you are asking about (for example with Linking (NOT Query) or become a PFObject as a result).

    I have understood your problem as being the following:

    • A series of CLLocationCoordinate2D are created by the user
    • You want to easily add these coordinates to the MKMapView
    • You want to easily store these coordinates in the Parse backend

    I think the best solution for you is to create a custom class which subclasses PFObject and implements MKAnnotation (I'm not quite sure what you mean by and that the only solution is to subclass the PFObject, which at its current state there is no help with that either.)

    I've tried to put together a sample project with the following three files. It's nice and clean since you can have the following three lines of code to achieve the two goals outlined above:

    let myAnnotation = MyAnnotation(coordinate: coordinate)
    mapView.addAnnotation(myAnnotation)
    myAnnotation.saveInBackground() // Handle this background save better
    

    Let me know if this helps with your problem, otherwise please rephrase your question to be more clear.


    UPDATE 1: OP wanted title, subtitle and image functionality.

    The title and subtitle properties are not unique to MKPointAnnotation, but rather a part of the MKAnnotation protocol, which is used to create the MyAnnotation in my example. This means you simply need to add these two properties to MyAnnotation in order to get the functionality you want.

    Concerning the image, then this is it not a unique feature for MKPinAnnotationView, but again for the more generic MKAnnotationView. In reality, the image property has not purpose in the MKPinAnnotationView. As described in the documentation for the image property:

    You can use the `MKAnnotationView` class as is or subclass it to provide custom behavior as needed. 
    The `image` property of the class lets you set the appearance of the annotation view without subclassing directly.
    

    When using the MKPinAnnotationView, then the view will always be a pin, which is why the image property has not purpose.

    So in order to use this image property, then you'll need to make use of MKAnnotationView in the delegation method mapView:viewForAnnotation: from MKMapViewDelegate.

    Remember to set the delegate property of the mapView (I've set it in the storyboard).

    I've updated my answer in order to reflect the changes.


    The code:

    //
    //  ViewController.swift
    //  ParseAnnotationFun
    //
    //  Created by Stefan Veis Pennerup on 28/01/16.
    //  Copyright © 2016 Kumuluzz. All rights reserved.
    //
    
    import UIKit
    import MapKit
    
    class ViewController: UIViewController, MKMapViewDelegate {
    
        // MARK: - Storyboard outlets
    
        @IBOutlet weak var mapView: MKMapView!
    
        // MARK: - Gesture Recognizers
    
        @IBAction func longPressed(sender: UILongPressGestureRecognizer) {
            print("longPressed")
            if sender.state != .Began { return }
    
            let touchPoint = sender.locationInView(mapView)
            let touchMapCoordinate = mapView.convertPoint(touchPoint, toCoordinateFromView: mapView)
            createAnnotation(touchMapCoordinate)
        }
    
        // MARK: - Model
    
        private func createAnnotation(coordinate: CLLocationCoordinate2D) {
            print("createAnnotation")
            let myAnnotation = MyAnnotation(coordinate: coordinate)
            mapView.addAnnotation(myAnnotation)
            myAnnotation.saveInBackground() // Handle this background save better
        }
    
        // MARK: - MKMapViewDelegate
    
        func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
            let id = "someIdentifier"
            var view = mapView.dequeueReusableAnnotationViewWithIdentifier(id)
    
            if view == nil {
                view = MKAnnotationView(annotation: annotation, reuseIdentifier: id)
                view?.canShowCallout = true
                view?.image = UIImage(named: "oranges")
            }
    
            view?.annotation = annotation
            return view
        }
    
    }    
    

    //
    //  MyAnnotation.swift
    //  ParseAnnotationFun
    //
    //  Created by Stefan Veis Pennerup on 28/01/16.
    //  Copyright © 2016 Kumuluzz. All rights reserved.
    //
    
    import Foundation
    import Parse
    import MapKit
    
    class MyAnnotation: PFObject, PFSubclassing, MKAnnotation {
    
        // MARK: - Properties
    
        @NSManaged var location: PFGeoPoint
    
        // MARK: - Initializers
    
        init(coordinate: CLLocationCoordinate2D) {
            super.init()
            location = PFGeoPoint(latitude: coordinate.latitude, longitude: coordinate.longitude)
        }
    
        override class func initialize() {
            struct Static {
                static var onceToken : dispatch_once_t = 0;
            }
            dispatch_once(&Static.onceToken) {
                self.registerSubclass()
            }
        }
    
        // MARK: - PFSubclassing protocol
    
        static func parseClassName() -> String {
            return "AnnotationPins"
        }
    
        // MARK: - MKAnnotation protocol
    
        var coordinate: CLLocationCoordinate2D {
            return CLLocationCoordinate2DMake(location.latitude, location.longitude)
        }
    
        var title: String? = "Awesome title"
    
        var subtitle: String? = "Random subtitle"
    
    }
    

    //
    //  AppDelegate.swift
    //  ParseAnnotationFun
    //
    //  Created by Stefan Veis Pennerup on 28/01/16.
    //  Copyright © 2016 Kumuluzz. All rights reserved.
    //
    
    import UIKit
    import Parse
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
    
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    
            MyAnnotation.initialize()
            Parse.setApplicationId("xxx",
            clientKey: "xxx")
    
            return true
        }
    
    }