Swift error: Cannot assign to property: 'coordinate' is immutable - swift

The problem is when I write this line of code on which I try to convert the user location to another coordinate, I get this error: Cannot assign to property: 'coordinate' is immutable
The code is:
var location = sender.location(in: self.mapView)
let locCoord = self.mapView.convert(location, toCoordinateFrom: self.mapView)
self.mapView.userLocation.coordinate = locCoord *// Cannot assign to property:'coordinate' is immutable*
Can you help please?

As the error says the coordibate property is immutable
var coordinate: CLLocationCoordinate2D { get }
var userLocation: CLLocation { get }
you can't alter it in addition to userLocation , if you need a different location go directly with

If your want to assign new value then use var instead of let , let is used to non changed values

Related

Assigning an accessibility identifier to an MKMapView object

I'm trying to configure snapshot for an app I'm working in, it already works in the english version but in the localized versions I don't know how to assign an accessibility identifier to a pin in the Map in MKMapView, somebody knows hows to do this?
Thanks.
Accessibility identifiers are a great way to separate your application's language from Xcode UI Testing. The identifier comes from UIAccessibilityIdentification which UIView already conforms to. However, neither NSObject nor MKAnnotation conform to the protocol. So you have to set that conformance yourself.
class Annotation: NSObject, MKAnnotation, UIAccessibilityIdentification {
let coordinate: CLLocationCoordinate2D
let title: String?
var accessibilityIdentifier: String?
init(title: String?, coordinate: CLLocationCoordinate2D) {
self.title = title
self.coordinate = coordinate
}
}
let coordinate = CLLocationCoordinate2DMake(40.703490, -73.987770)
let annotation = Annotation(title: "BeerMenus HQ", coordinate: coordinate)
annotation.accessibilityIdentifier = "Custom Identifier"
let mapView = MKMapView()
mapView.addAnnotation(annotation)
Then under test you can reference the annotation via otherElements.
let app = XCUIApplication()
let annotation = app.maps.element.otherElements["Custom Identifier"]
annotation.tap()

MapView crashes with setting to delegate

I am setting my map view to delegate yet so I can place an annotation callout on my pin, but I have a geocode that does something else only when a button is clicked. When I set the map view to delegate and I try to place a pin it crashes. How can I fix this?
func action(gestureRecognizer:UIGestureRecognizer) {
let touchPoint = gestureRecognizer.locationInView(self.mapView)
let newCoord:CLLocationCoordinate2D = mapView.convertPoint(touchPoint, toCoordinateFromView: self.mapView)
//var newAnotation = MKPointAnnotation()
//
self.mapView.delegate = self
//
self.newAnotation = MKPointAnnotation()
self.newAnotation.coordinate = newCoord
newAnotation.title = "New Location"
newAnotation.subtitle = "New Subtitle"
//mapView.addAnnotation(newAnotation)
self.pinAnnotationView = MKPinAnnotationView(annotation: self.newAnotation, reuseIdentifier: nil)
self.mapView.centerCoordinate = self.newAnotation.coordinate
self.mapView.addAnnotation(self.pinAnnotationView.annotation!)
}
Screenshot of where it crashes,
You must be getting the following error log in your console output.And thats because you have not initialise your geoCoder instance.
fatal error: unexpectedly found nil while unwrapping an Optional value
Declare it like this
var geoCoder: CLGeocoder = CLGeocoder()

How to customize multiple annotations? Parse-Swift

I have been struggling with this for days but I still can't find a way to do it. Basically I have this map view and I am getting the annotations data (location,title,subtitle) from Parse, all I want to do is to replace the default pins with a custom one, I managed to customize one when I only use one annotation but for multiple it is not working, this is what I have for adding the annotations:
func setAnnotations(){
//Run query and get objects from parse, then add annotations
var query = PFQuery(className: "Countries")
query.orderByDescending("Location")
query.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]?,error: NSError?)-> Void in
if error == nil{
let myObjects = objects as! [PFObject]
for object in myObjects{
//data for annotation
var annotation = MKPointAnnotation()
let place = object["Location"] as? PFGeoPoint
let placeName = object["nameEnglish"] as? String
annotation.title = placeName
annotation.subtitle = placeName
annotation.coordinate = CLLocationCoordinate2DMake(place!.latitude,place!.longitude)
//add annotations
self.mapView.addAnnotation(annotation)
}
}else{println(error)}
}
}
How would I apply the "dequeueReusableAnnotationViewWithIdentifier" here?
You will want to use the viewForAnnotation delegate method similar to this answer. Make sure you also implement the MKMapViewDelegate protocol and set your controller to be the delegate.
Other than that, all you need to do is update your query to create and add your custom annotations like you are right now.
Cheers,
Russell

viewForAnnotation not being called (using Alamofire to parse JSON)

I'm new to iOS programming. I prefer to use Swift.
What I'm trying to do is call a web service that returns some JSON, parse the JSON into a custom object called Entry and plot those entries on a map.
I am using AlamoFire to make the web service call and SwiftyJSON to parse the JSON into Entry objects like below
request(.GET, URLString: "https://myURLThatReturnsJson")
.responseJSON { (_, _, json, error) in
if let json: AnyObject = json{
let jsonEntries = JSON(json)
for result in jsonEntries["entries"].arrayValue {
let business_name = result["business_name"].stringValue
let latitude = result["lat"].stringValue
let longitude = result["lng"].stringValue
let category = result["category"].stringValue
let address = result["address"].stringValue
let city = result["city"].stringValue
let type = result["type"].stringValue
let location = result["location"].stringValue
let valid = result["valid"].stringValue
let comments = result["comments"].stringValue
let date = result["date"].stringValue
let username = result["username"].stringValue
let additional_comment_count = result["additional_comment_count"].stringValue
let entry : Entry = Entry(
business_name: business_name,
latitude: latitude,
longitude: longitude,
category: category,
address: address,
city: city,
type: type,
location: location,
valid: valid,
comments: comments,
date: date,
username: username,
additional_comment_count: additional_comment_count,
title: business_name,
subtitle: location,
coordinate: CLLocationCoordinate2D(latitude: (latitude as NSString).doubleValue, longitude: (longitude as NSString).doubleValue))
entries.append(entry)
}
// Now we have our array of entries. Now plot them.
for entry in entries{
self.mapView.addAnnotation(entry)
}
}
}
So as you can see in the code above I am also mapping the entries within the AlamoFire request (don't know if this is bad because AlamoFire is done on a separate thread I believe).
I also have a viewForAnnotations method that looks like below
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
print("viewForAnnotation called")
return nil
}
My viewForAnnotation method is not being called at all (break point on print line is not being hit).
Any help is appreciated!
Please make sure to set the delegate property of mapview to self.
mapview.delegate = self
You can also do this by connecting the delegate outlet of mapview to ViewController using Connection Inspector (Interface Builder)

Using MapKit within the MVC guildines

All,
I am trying to follow MVC guidelines with my app, so I am removing the code from the View (View Controller). I am trying to get a MapKit displayed with lat/long from Parse. I have it working fine when I enter the lat/long manually.
So I want a computed property (I think) on the tuple. The tuple will hold the lat/long. When the tuple is used, I want to execute the parse query to retrieve the lat/long.
I am a little stuck putting a computed property on a tuple.
Here is my code.
var latAndlongTuple = (Double, Double)?
{
var query = PFQuery(className: "TableViewData")
query.includeKey("EventLoc")
query.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
for object in objects {
var EventLocation = object["EventLoc"] as PFObject!
EventLocation.fetchIfNeededInBackgroundWithBlock {
(EventLocation: PFObject!, error: NSError!) -> Void in
dispatch_async(dispatch_get_main_queue()) {
let longitude = EventLocation["Latitude"] as NSString
let latitude = EventLocation["Longitude"] as NSString
}
func LocationCoordinate() -> MKCoordinateRegion
{
let location = CLLocationCoordinate2D(latitude: latAndlongTuple.0 ,longitude: latAndlongTuple.1)
let span = MKCoordinateSpanMake(0.001, 0.001)
let region = MKCoordinateRegion(center: location, span: span)
return region
}
So when the tuple is executed when the function LocationCoordinate is executed, I want the parse code running in the tuple computed property. Then it updates the segments of the tuple with the lat/long.
Any questions let me know.
I have done this by :
var latAndlongTuple:(lat : CLLocationDegrees, long : CLLocationDegrees)
{
get {
return (52.606907, -1.104780)
}
}
and instead of just returning the 2 values, I have used Parse to to get the values and then returned the CLLocationDegree tuple.