Silver Challenge without using MKMapViewDelegate

#1

This challenge is really frustrating. Took me a couple of days but I finally made it work.
Hopefully, my code below will be of some help to those who are stuck.

After several attempts, I still could not integrate any of MKMapViewDelegate’s functions. If you were successful in using it, please let me know.

  1. Add a button in loadView().

[code]let currentLocationButton = UIButton(type: UIButtonType.System)
currentLocationButton.frame = CGRect(x: 16, y: 80, width: 50, height: 50)
currentLocationButton.titleLabel?.font = UIFont.systemFontOfSize(12)
currentLocationButton.setTitle(“Where Am I?”, forState: .Normal)
currentLocationButton.sizeToFit()
currentLocationButton.backgroundColor = UIColor.greenColor()
currentLocationButton.addTarget(self, action: “navigateToCurrentLocation:”, forControlEvents: .TouchUpInside)

view.addSubview(currentLocationButton)[/code]

  1. Initialize and declare CLLocationManager outside any functions.
    Apple docs say that the location manager has to have a strong reference. This seems to do the trick.
  1. Open your project’s info.plist and add the key NSLocationWhenInUseUsageDescription. This is the string that your app present’s the user when it asks for authorization to use location services.

  2. Create the function that the button calls. In my case, this is navigateToCurrentLocation

[code]func navigateToCurrentLocation(button: UIButton) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation

    let authorizationStatus = CLLocationManager.authorizationStatus()
    
    if authorizationStatus == .NotDetermined {
        locationManager.requestWhenInUseAuthorization()
    } else if (authorizationStatus == .AuthorizedAlways || authorizationStatus == .AuthorizedWhenInUse) {
        print("authorized. requesting location")
        locationManager.requestLocation()
    }

}[/code]

  1. Documentation for the method requestWhenInUseAuthorization mentions that it calls locationManager:didChangeAuthorizationStatus: upon user authorization.
    I implemented it as:

[code]func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(“locations updated”)
if let latestCurrentLocation = locations.last {
print(“latestCurrentLocation: (latestCurrentLocation)”)

        // call the mapkit's methods to center your map
        let zoomedInCurrentLocation = MKCoordinateRegionMakeWithDistance(latestCurrentLocation.coordinate, 500, 500)
        mapView.setRegion(zoomedInCurrentLocation, animated: true)
        mapView.showsUserLocation = true
    }
}[/code]
#2

It’s been discussed.

Nice. That saves some steps.

#3

Should you want to position the button w/ auto layout let’s say centered horizontally and just above the bottom layout guide for horizontal n vertical orientation, you can use either NSLayoutAnchor style (iOS 9.0) or NSLayoutConstraint style:

//*** NSLayoutAnchor style
let widthConstraint = locateMeButton.widthAnchor.constraintEqualToAnchor(nil, constant: 100.0)
let heightConstraint = locateMeButton.heightAnchor.constraintEqualToAnchor(nil, constant: 35.0)
let horizontalConstraint = locateMeButton.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor)
let verticalConstaint = locateMeButton.bottomAnchor.constraintEqualToAnchor(self.bottomLayoutGuide.topAnchor, constant: -28.0)
NSLayoutConstraint.activateConstraints([widthConstraint, heightConstraint, horizontalConstraint, verticalConstraint])

//*** NSLayoutConstraint style
let horizontalConstraint = NSLayoutConstraint(item: locateMeButton, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
self.view.addConstraint(horizontalConstraint)
        
let verticalConstraint = NSLayoutConstraint(item: locateMeButton, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self.bottomLayoutGuide, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: -28.0)
self.view.addConstraint(verticalConstraint)
        
let widthConstraint = NSLayoutConstraint(item: locateMeButton, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100)
self.view.addConstraint(widthConstraint)
        
let heightConstraint = NSLayoutConstraint(item: locateMeButton, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.view.addConstraint(heightConstraint)

Other style (i.e., visual format style, which I can’t figure out on how to apply to obtain the same result as above) can be found here: stackoverflow.com/questions/2618 … 2#26181982

#4

[quote=“moringatree”]
4. Create the function that the button calls. In my case, this is navigateToCurrentLocation

[code]func navigateToCurrentLocation(button: UIButton) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation

    let authorizationStatus = CLLocationManager.authorizationStatus()
    
    if authorizationStatus == .NotDetermined {
        locationManager.requestWhenInUseAuthorization()
    } else if (authorizationStatus == .AuthorizedAlways || authorizationStatus == .AuthorizedWhenInUse) {
        print("authorized. requesting location")
        locationManager.requestLocation()
    }

}[/code]

  1. Documentation for the method requestWhenInUseAuthorization mentions that it calls locationManager:didChangeAuthorizationStatus: upon user authorization.
    I implemented it as:

[code]func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(“locations updated”)
if let latestCurrentLocation = locations.last {
print(“latestCurrentLocation: (latestCurrentLocation)”)

        // call the mapkit's methods to center your map
        let zoomedInCurrentLocation = MKCoordinateRegionMakeWithDistance(latestCurrentLocation.coordinate, 500, 500)
        mapView.setRegion(zoomedInCurrentLocation, animated: true)
        mapView.showsUserLocation = true
    }
}[/code][/quote]

heres how I got mine to work:

[code] func findMe(){
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
mapView.showsUserLocation = true
}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let userLocation:CLLocation = locations[0] as CLLocation
    
    manager.stopUpdatingLocation()

    let location = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)
    let span = MKCoordinateSpanMake(0.5, 0.5)
    let region = MKCoordinateRegion(center: location, span: span)
    
    mapView.setRegion(region, animated: true)
}

[/code]