Stevic Stevic - 3 months ago 27
Swift Question

Error message: whose view is not in the window hierarchy - Swift

I got a error when i wants to present a new view. Here is my code. I got this error: Warning: Attempt to present on whose view is not in the window hierarchy!

It shows the new view (LoginController) and everything works fine. But why I got these error and how can I fix it?

ViewController:

import UIKit
import MapKit
import Firebase
import SwiftyJSON

class FriendsController: UICollectionViewController, UICollectionViewDelegateFlowLayout, CLLocationManagerDelegate, MKMapViewDelegate {

var window: UIWindow?
var mapView: MKMapView?
let locationManager = CLLocationManager()

let distanceSpan: Double = 500


private let cellId = "cellId"


override func viewDidLoad() {
super.viewDidLoad()

navigationItem.title = "Current Location"

navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Logout", style: .Plain, target: self, action: #selector(handleLogout))

// user is not logged in
if FIRAuth.auth()?.currentUser?.uid == nil {
performSelector(#selector(handleLogout), withObject: nil, afterDelay: 0)
}

collectionView?.backgroundColor = UIColor.redColor()

collectionView?.backgroundColor = UIColor.whiteColor()
collectionView?.alwaysBounceVertical = true

self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.view.backgroundColor = UIColor.whiteColor()

self.mapView = MKMapView(frame: CGRectMake(0, 20, (self.window?.frame.width)!, (self.window?.frame.height)!))
self.view.addSubview(self.mapView!)

self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView!.showsUserLocation = true

checkIfUserLoggedIn()

}

func checkIfUserLoggedIn() {
if FIRAuth.auth()?.currentUser?.uid == nil {
performSelector(#selector(handleLogout), withObject: nil, afterDelay: 0)
handleLogout()

}

}

func handleLogout() {

do {
try FIRAuth.auth()?.signOut()
} catch let logoutError {
print(logoutError)
}

let loginController = LoginController()
presentViewController(loginController, animated: true, completion: nil)

}

func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
if let mapView = self.mapView {
let region = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, self.distanceSpan, self.distanceSpan)
mapView.setRegion(region, animated: true)
mapView.showsUserLocation = true
}
}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last

let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)

let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))

self.mapView!.setRegion(region, animated: true)

// let anotation = MKPointAnnotation()
// anotation.coordinate = center
// anotation.title = "The Location"
// anotation.subtitle = "This is the location!"
// mapView!.addAnnotation(anotation)

self.locationManager.stopUpdatingLocation()


}


func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print("Errors: " + error.localizedDescription)
}




}


LoginController:

import UIKit
import Firebase

class LoginController: UIViewController {

let inputsContainerView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.whiteColor()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 5
view.layer.masksToBounds = true
return view

}()

lazy var loginRegisterButton: UIButton = {
let button = UIButton(type: .System)
button.backgroundColor = UIColor(r: 80, g: 101, b: 161)
button.setTitle("Register", forState: .Normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
button.titleLabel?.font = UIFont.boldSystemFontOfSize(16)

button.addTarget(self, action: #selector(handleLoginRegister), forControlEvents: .TouchUpInside)

return button
}()

func handleLoginRegister() {
if loginRegisterSegmentedControl.selectedSegmentIndex == 0 {
handleLogin()
} else {
handleRegister()
}
}

func handleLogin() {
guard let email = emailTextField.text, password = passwordTextField.text else {
print("Form is not valid")
return
}

FIRAuth.auth()?.signInWithEmail(email, password: password, completion: { (user, error) in

if error != nil {
print(error)
return
}

self.dismissViewControllerAnimated(true, completion: nil)

})


}



func handleRegister() {
guard let email = emailTextField.text, password = passwordTextField.text, name = nameTextField.text else {
print("Form is not valid")
return
}

FIRAuth.auth()?.createUserWithEmail(email, password: password, completion: { (user: FIRUser?, error) in

if error != nil {
print(error)
return
}

guard let uid = user?.uid else {
return
}

//successfully autheticated user
let ref = FIRDatabase.database().referenceFromURL("https://placetaggertabbarmenu.firebaseio.com")
let usersReference = ref.child("users").child(uid)
let values = ["name": name, "email": email]
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref) in

if error != nil {
print(err)
return
}

self.dismissViewControllerAnimated(true, completion: nil)

})

})

}



let nameTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Name"
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()

let nameSeparatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(r: 220, g: 220, b: 220)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()

let emailTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Email"
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()

let emailSeparatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(r: 220, g: 220, b: 220)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()

let passwordTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Password"
tf.translatesAutoresizingMaskIntoConstraints = false
tf.secureTextEntry = true
return tf

}()

lazy var loginRegisterSegmentedControl: UISegmentedControl = {
let sc = UISegmentedControl(items: ["Login", "Register"])
sc.translatesAutoresizingMaskIntoConstraints = false
sc.tintColor = UIColor.whiteColor()
sc.selectedSegmentIndex = 1
sc.addTarget(self, action: #selector(handleLoginRegisterChange), forControlEvents: .ValueChanged)
return sc
}()

lazy var profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "Facebook Profile Pic")
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .ScaleAspectFill

imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectProfileImageView)))
imageView.userInteractionEnabled = true


return imageView

}()

func handleLoginRegisterChange() {
let title = loginRegisterSegmentedControl.titleForSegmentAtIndex(loginRegisterSegmentedControl.selectedSegmentIndex)
loginRegisterButton.setTitle(title, forState: .Normal)

// change height of inputContainerView
inputsContainerViewHeigtAnchor?.constant = loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 100 : 150

// change heigt of nameTextField
nameTextFieldHeightAnchor?.active = false
nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraintEqualToAnchor(inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 0 : 1/3)
nameTextFieldHeightAnchor?.active = true

emailTextFieldHeightAnchor?.active = false
emailTextFieldHeightAnchor = emailTextField.heightAnchor.constraintEqualToAnchor(inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3)
emailTextFieldHeightAnchor?.active = true

passwordTextFieldHeightAnchor?.active = false
passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraintEqualToAnchor(inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3)
passwordTextFieldHeightAnchor?.active = true



}



override func viewDidLoad() {
super.viewDidLoad()

view.backgroundColor = UIColor(r: 61, g: 91, b: 151)

view.addSubview(inputsContainerView)
view.addSubview(loginRegisterButton)
view.addSubview(profileImageView)
view.addSubview(loginRegisterSegmentedControl)


setupInputsContainerView()
setupLoginRegisterButton()
setupProfileImageView()
setupLoginRegisterSegmentedControl()

}

func setupProfileImageView() {
//need x, y, width, height constraints
profileImageView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
profileImageView.bottomAnchor.constraintEqualToAnchor(inputsContainerView.topAnchor, constant: -60).active = true
profileImageView.widthAnchor.constraintEqualToConstant(150).active = true
profileImageView.heightAnchor.constraintEqualToConstant(150).active = true
}

func setupLoginRegisterSegmentedControl() {

//need x, y, widht, heigt constraints
loginRegisterSegmentedControl.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
loginRegisterSegmentedControl.bottomAnchor.constraintEqualToAnchor(inputsContainerView.topAnchor, constant: -12).active = true
loginRegisterSegmentedControl.widthAnchor.constraintEqualToAnchor(inputsContainerView.widthAnchor).active = true
loginRegisterSegmentedControl.heightAnchor.constraintEqualToConstant(30).active = true


}

var inputsContainerViewHeigtAnchor: NSLayoutConstraint?
var nameTextFieldHeightAnchor: NSLayoutConstraint?
var emailTextFieldHeightAnchor: NSLayoutConstraint?
var passwordTextFieldHeightAnchor: NSLayoutConstraint?

func setupInputsContainerView() {

//need x, y, widht, heigt constraints
inputsContainerView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
inputsContainerView.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor).active = true
inputsContainerView.widthAnchor.constraintEqualToAnchor(view.widthAnchor, constant: -24).active = true
inputsContainerViewHeigtAnchor = inputsContainerView.heightAnchor.constraintEqualToConstant(150)
inputsContainerViewHeigtAnchor?.active = true

inputsContainerView.addSubview(nameTextField)
inputsContainerView.addSubview(nameSeparatorView)
inputsContainerView.addSubview(emailTextField)
inputsContainerView.addSubview(emailSeparatorView)
inputsContainerView.addSubview(passwordTextField)


//need x, y, widht, heigt constraints
nameTextField.leftAnchor.constraintEqualToAnchor(inputsContainerView.leftAnchor, constant: 12).active = true
nameTextField.topAnchor.constraintEqualToAnchor(inputsContainerView.topAnchor).active = true
nameTextField.widthAnchor.constraintEqualToAnchor(inputsContainerView.widthAnchor).active = true
nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraintEqualToAnchor(inputsContainerView.heightAnchor, multiplier: 1/3)
nameTextFieldHeightAnchor?.active = true

//need x, y, widht, heigt constraints
nameSeparatorView.leftAnchor.constraintEqualToAnchor(inputsContainerView.leftAnchor).active = true
nameSeparatorView.topAnchor.constraintEqualToAnchor(nameTextField.bottomAnchor).active = true
nameSeparatorView.widthAnchor.constraintEqualToAnchor(inputsContainerView.widthAnchor).active = true
nameSeparatorView.heightAnchor.constraintEqualToConstant(1).active = true

//need x, y, widht, heigt constraints
emailTextField.leftAnchor.constraintEqualToAnchor(inputsContainerView.leftAnchor, constant: 12).active = true
emailTextField.topAnchor.constraintEqualToAnchor(nameTextField.bottomAnchor).active = true
emailTextField.widthAnchor.constraintEqualToAnchor(inputsContainerView.widthAnchor).active = true
emailTextFieldHeightAnchor = emailTextField.heightAnchor.constraintEqualToAnchor(inputsContainerView.heightAnchor, multiplier: 1/3)
emailTextFieldHeightAnchor?.active = true

//need x, y, widht, heigt constraints
emailSeparatorView.leftAnchor.constraintEqualToAnchor(inputsContainerView.leftAnchor).active = true
emailSeparatorView.topAnchor.constraintEqualToAnchor(emailTextField.bottomAnchor).active = true
emailSeparatorView.widthAnchor.constraintEqualToAnchor(inputsContainerView.widthAnchor).active = true
emailSeparatorView.heightAnchor.constraintEqualToConstant(1).active = true

//need x, y, widht, heigt constraints
passwordTextField.leftAnchor.constraintEqualToAnchor(inputsContainerView.leftAnchor, constant: 12).active = true
passwordTextField.topAnchor.constraintEqualToAnchor(emailTextField.bottomAnchor).active = true
passwordTextField.widthAnchor.constraintEqualToAnchor(inputsContainerView.widthAnchor).active = true
passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraintEqualToAnchor(inputsContainerView.heightAnchor, multiplier: 1/3)
passwordTextFieldHeightAnchor?.active = true



}

func setupLoginRegisterButton() {
//need x, y, widht, heigt constraints

loginRegisterButton.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
loginRegisterButton.topAnchor.constraintEqualToAnchor(inputsContainerView.bottomAnchor, constant: 12).active = true
loginRegisterButton.widthAnchor.constraintEqualToAnchor(inputsContainerView.widthAnchor).active = true
loginRegisterButton.heightAnchor.constraintEqualToConstant(40).active = true

}

override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}

}

extension UIColor {

convenience init(r: CGFloat, g: CGFloat, b: CGFloat) {
self.init(red: r/255, green: g/255, blue: b/255, alpha: 1 )
}
}

Answer

The view might not be in the view hierarchy when the view is loaded. Try moving the call to viewDidAppear. You're also calling this twice:

 if FIRAuth.auth()?.currentUser?.uid == nil {
    performSelector(#selector(handleLogout), withObject: nil, afterDelay: 0)
} 

so remove one of them.