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 trialDamion Marshall
iOS Development Techdegree Student 5,594 PointsKeep getting 'Attempting to present UIAlertController whose view is not in the window hierarchy!'
Below is my code. I'm in a split view controller using navigation controllers to present views. I'm just trying to present an alert view controller modally for when the user declines location services. Below is my code how do I proceed?
import Foundation
import CoreLocation
import UIKit
final class LocationManager: NSObject, CLLocationManagerDelegate {
let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
}
func getPermission() {
switch CLLocationManager.authorizationStatus() {
case .AuthorizedWhenInUse: manager.startUpdatingLocation()
case .AuthorizedAlways: manager.startUpdatingLocation()
case .NotDetermined: manager.requestWhenInUseAuthorization()
case .Restricted, .Denied:
let alertController = UIAlertController(
title: "Background Location Access Disabled", message: "To view restaurants, Open settings and set location acccess to 'Always', or 'When in Use'.",
preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alertController.addAction(cancelAction)
let openAction = UIAlertAction(title: "Open Settings", style: .Default) { (action) in
if let url = NSURL(string: UIApplicationOpenSettingsURLString) {
UIApplication.sharedApplication().openURL(url)
}
}
alertController.addAction(openAction)
let splitViewController = UIApplication.sharedApplication().windows[0].rootViewController as! UISplitViewController
let activeViewController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
activeViewController.topViewController!.presentViewController(alertController, animated: true, completion: nil)
}
}
}
1 Answer
Greg Kaleka
39,021 PointsHi Damion,
If you're calling this method from a view controller, I would suggest modifying the method to take the sender as a parameter. If you do, you'll skip all the back bending to figure out which view should do the presenting.
func getPermission(sendingVC: UIViewController) {
// other stuff //
alertController.addAction(openAction)
sendingVC.presentViewController(alertController, animated: true, completion: nil)
Not only is this a lot cleaner, but it's much more versatile. If you want to have a different VC asking for permission, all you have to do is call the method from somewhere else, rather than figuring out how to get that different VC to present the alert. This is a clear win by separating concerns. The location manager shouldn't be worried about which UIViewController presents the alert.
You may even want to take this a step further and create a new class that handles the alert stuff, as that really shouldn't be the concern of a location manager either... This is a good first step, though.