Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Restaurant Reviews App - Cannot update button when location permission is allowed by user.

When I allow the location request on the simulator, the button does not update as defined in authorizationSuceeded().

See permissions controller and location manager classes.

import UIKit
import OAuth2
import CoreLocation

class PermissionsController: UIViewController, LocationPermissionsDelegate {

    let oauth = OAuth2ClientCredentials(settings: [
            "client_id": "n2p6xlomYrHxVlbwOyN9fQ",
            "client_secret": "9Z9PgLquQ6gSRGWJpY4PwJC3bBBKpS2qxcLQsKyEd44Hd78crGZsk3Ac7r48jrJd",
            "authorize_uri": "https://api.yelp.com/oauth2/token",
            "secret_in_body": true,
            "keychain": false
        ])

    lazy var locationManager: LocationManager = {
        return LocationManager(permissionsDelegate: self)
    }()

    var isAuthorizedForLocation: Bool
    var isAuthenticatedWithToken: Bool

    lazy var locationPermissionButton:  UIButton = {
        let title = self.isAuthorizedForLocation ? "Location Permissions Granted" : "Request Location Permissions"
        let button = UIButton(type: .system)
        let controlState = self.isAuthorizedForLocation ? UIControlState.disabled : UIControlState.normal
        button.isEnabled = !self.isAuthorizedForLocation
        button.setTitle(title, for: controlState)
        button.addTarget(self, action: #selector(PermissionsController.requestLocationPermissions), for: .touchUpInside)

        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor(red: 62/255.0, green: 71/255.0, blue: 79/255.0, alpha: 1.0)
        button.setTitleColor(UIColor(red: 178/255.0, green: 187/255.0, blue: 185/255.0, alpha: 1.0), for: .disabled)
        button.setTitleColor(.white, for: .normal)
        button.layer.cornerRadius = 5
        button.clipsToBounds = true

        return button
    }()

    lazy var oauthTokenButton:  UIButton = {
        let title = self.isAuthenticatedWithToken ? "OAuth Token Granted" : "Request OAuth Token"
        let button = UIButton(type: .system)
        let controlState = self.isAuthenticatedWithToken ? UIControlState.disabled : UIControlState.normal
        button.isEnabled = !self.isAuthenticatedWithToken
        button.setTitle(title, for: controlState)
        button.addTarget(self, action: #selector(PermissionsController.requestOAuthToken), for: .touchUpInside)

        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor(red: 62/255.0, green: 71/255.0, blue: 79/255.0, alpha: 1.0)
        button.setTitleColor(UIColor(red: 178/255.0, green: 187/255.0, blue: 185/255.0, alpha: 1.0), for: .disabled)
        button.setTitleColor(.white, for: .normal)
        button.layer.cornerRadius = 5
        button.clipsToBounds = true

        return button
    }()

    lazy var activityIndicator: UIActivityIndicatorView = {
        let indicator = UIActivityIndicatorView(activityIndicatorStyle: .white)

        indicator.hidesWhenStopped = true
        indicator.translatesAutoresizingMaskIntoConstraints = false
        return indicator
    }()

    lazy var dismissButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Dismiss", for: .normal)
        button.tintColor = .white
        button.addTarget(self, action: #selector(PermissionsController.dismissPermissions), for: .touchUpInside)

        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    required init?(coder aDecoder: NSCoder) {
        fatalError("init coder not implemented")
    }

    init(isAuthorizedForLocation authorized: Bool, isAuthenticatedWithToken authenticated: Bool) {
        self.isAuthorizedForLocation = authorized
        self.isAuthenticatedWithToken = authenticated
        super.init(nibName: nil, bundle: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(red: 95/255.0, green: 207/255.0, blue: 128/255.0, alpha: 1.0)
    }


    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        let stackView = UIStackView(arrangedSubviews: [locationPermissionButton, oauthTokenButton])
        stackView.alignment = .center
        stackView.axis = .vertical
        stackView.distribution = .equalSpacing
        stackView.spacing = 16.0
        stackView.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(stackView)
        view.addSubview(dismissButton)
        view.addSubview(activityIndicator)

        NSLayoutConstraint.activate([
            locationPermissionButton.heightAnchor.constraint(equalToConstant: 64.0),
            locationPermissionButton.leadingAnchor.constraint(equalTo: stackView.leadingAnchor),
            locationPermissionButton.trailingAnchor.constraint(equalTo: stackView.trailingAnchor),
            oauthTokenButton.heightAnchor.constraint(equalToConstant: 64.0),
            oauthTokenButton.leadingAnchor.constraint(equalTo: stackView.leadingAnchor),
            oauthTokenButton.trailingAnchor.constraint(equalTo: stackView.trailingAnchor),
            stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 32.0),
            stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -32.0),
            dismissButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -16),
            dismissButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 175),
            activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        ])
    }

    @objc func requestLocationPermissions() {
        do {
            try locationManager.requestLocationAuthorisation()
        } catch LocationError.disallowedByUser {
            // show alert to user
        } catch let error {
            print("Location Authorisation Error: \(error.localizedDescription)")
        }
    }

    @objc func requestOAuthToken() {

        self.activityIndicator.startAnimating()

        oauth.authorize { authParams, error in


            if let params = authParams {
                guard let token = params["access_token"] as? String,
                    let expiration = params["expires_in"] as? TimeInterval else {
                    return
                }

                let account = YelpAccount(accessToken: token, expiration: expiration, grantDate: Date())
                do {
                    try account.save()
                    self.oauthTokenButton.setTitle("Oauth Token Granted", for: .disabled)
                    self.oauthTokenButton.isEnabled = false
                    self.activityIndicator.stopAnimating()
                } catch let error {
                    print(error)
                    self.oauthTokenButton.setTitle("Error", for: .disabled)
                    self.oauthTokenButton.isEnabled = false
                    self.activityIndicator.stopAnimating()
                }
            } else {
                print("Authorisation was cancelled or went wrong: \(error!)")
            }
        }
    }

    @objc func dismissPermissions() {
        dismiss(animated: true, completion: nil)
    }

    // MARK: Location Permissions Delegate

    func authorizationSucceeded() {
        locationPermissionButton.setTitle("Location Permissions Granted", for: .disabled)
        locationPermissionButton.isEnabled = false
    }

    func authorizationFailedWithStatus(_ status: CLAuthorizationStatus) {
        //
    }
}
import Foundation
import CoreLocation

enum LocationError: Error {
    case unknownError
    case disallowedByUser
    case unableToFindLocation
}

protocol LocationPermissionsDelegate: class {
    func authorizationSucceeded()
    func authorizationFailedWithStatus(_ status: CLAuthorizationStatus)
}

// if location services implementation failes - check to see if the appropriate location services are available for you to use, as described in 'Determining the Availability of Location Services'.

class LocationManager: NSObject, CLLocationManagerDelegate {
    // 3. Create an instance of the CLLocationManager class and store a strong reference to it somewhere in your app.
    private let manager = CLLocationManager()
    weak var permissionsDelegate: LocationPermissionsDelegate?

    init(permissionsDelegate: LocationPermissionsDelegate?) {
        self.permissionsDelegate = permissionsDelegate
        super.init()
        manager.delegate = self
    }

    func requestLocationAuthorisation() throws {
        let authorisationStatus = CLLocationManager.authorizationStatus()

        // 1. Check to see if your app is authorized to use location services and request permission if your app's authorization status is not yet determined, as described in Requesting Permission to Use Location Services.
        if authorisationStatus == .restricted || authorisationStatus == .denied {
            throw LocationError.disallowedByUser
        } else if authorisationStatus == .notDetermined {
            // making location authorisation request
            manager.requestWhenInUseAuthorization()
        } else {
            return
        }

        func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
            if status == .authorizedWhenInUse {
                permissionsDelegate?.authorizationSucceeded()
            } else {
                permissionsDelegate?.authorizationFailedWithStatus(status)
            }
        }
    }
}

Any help would be greatly appreciated.

Thank you,

Mitch

1 Answer

Whoops. Simple syntactical error.

Placed locationManager(didChangeAuthorisation:) within requestionLocationAuthorisation().

All fixed.

Thank you,

Mitch