Why a view (Activity indicator) not getting disappeared? - ios

I've written almost identical code for another function and it works - but for some reason isn't working here. I just want to add this gray view with the activity indicator while the API is retrieving data from the server, and then hide it when the servers returns the data... the error label is updated appropriately, but the view never disappears... (grayLoadingView - this view contains the activity indicator)
#objc private func signUpButtonPressed() {
print("sign up pressed")
if validateTextFields() {
**//start activity indicator
grayLoadingView.isHidden = false**
createNewUser(username: usernameTextField.text!, email: emailTextField.text!, password: passwordTextField.text!, completionHandler: { (message) in
print("message-> \(message)")
**//hide activity indicator
self.grayLoadingView.isHidden = true**
if message == "Account created successfully" {
OperationQueue.main.addOperation {
self.dismiss(animated: false, completion: nil)
let nextScreen = HomeScreenViewController()
nextScreen.username = self.usernameTextField.text!
let newNavController = UINavigationController(rootViewController: nextScreen)
self.present(newNavController, animated: true, completion: nil)
}
} else {
DispatchQueue.main.async {
//display error message
self.errorLabel.isHidden = false
self.errorLabel.text = message
}
}
})
} else {
print("empty")
}
}

Related

Swift Segue - while an existing transition or presentation is occurring; the navigation stack will not be updated

The segue works fine when triggered outside the updatePassword func.
Full error -
'2020-07-03 13:17:34.656198+0100 FindingTaylorSwift[5305:154832] pushViewController:animated: called on <UINavigationController 0x7fc6a2037600> while an existing transition or presentation is occurring; the navigation stack will not be updated.'
#IBAction func updatePasword(_ sender: UIButton) {
.....
_ = self.awsUserPoolUpdatePassword.updatePasswordWithConfirmationCodeError?
.subscribe({ errorText in
guard let elementContent = errorText.element?.localizedDescription else { return }
switch elementContent {
case "The operation couldn’t be completed. (AWSMobileClient.AWSMobileClientError error 2.)":
self.showAlert(title: UpdatePasswordError.titleCode, message: UpdatePasswordError.messageCode)
case "The operation couldn’t be completed. (AWSMobileClient.AWSMobileClientError error 8.)":
self.showAlert(title: UpdatePasswordError.titlePassword, message: UpdatePasswordError.messagePasswordShort)
case "The operation couldn’t be completed. (AWSMobileClient.AWSMobileClientError error 9.)":
self.showAlert(title: UpdatePasswordError.titlePassword, message: UpdatePasswordError.messagePasswordComplexity)
default:
self.showAlert(title: UpdatePasswordError.titleDefault, message: UpdatePasswordError.messageDefault)
}
})
_ = self.awsUserPoolUpdatePassword.updatePasswordWithConfirmationCodeResult?
.subscribe({ resultText in
guard let elementContent = resultText.element?.forgotPasswordState else { return }
switch elementContent {
case .done:
self.showAlert(title: PasswordUpated.title, message: "")
self.transitionToLogin()
default:
self.showAlert(title: UpdatePasswordError.titleDefault, message: UpdatePasswordError.messageDefault)
}
})
}
private func transitionToLogin() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.performSegue(withIdentifier: AWSControllers.awsUpdatedPasswordSuccess, sender: self)
}
// DispatchQueue.main.async {
// self.performSegue(withIdentifier: AWSControllers.awsUpdatedPasswordSuccess, sender: self)
// }
}
AWS Class
internal func updatePasswordWithConfirmationCode(newPassword: String, confirmationCode: String) {
guard let username = self.awsUserNameEmail else { return }
let result = AWSMobileClient.default().rx.confirmForgotPassword(username: username, newPassword: newPassword, confirmationCode: confirmationCode)
.materialize()
result
.compactMap { $0.element }
.subscribe(onNext: { forgotPasswordResult in
switch forgotPasswordResult.forgotPasswordState {
case .done:
print("Password changed successfully")
self.userPasswordUpdateStatus = .passwordUpdateSuccessful
default:
print("Error: Could not change password.")
}
})
.disposed(by: disposeBag)
updatePasswordWithConfirmationCodeError = result.compactMap { $0.error }
updatePasswordWithConfirmationCodeResult = result.compactMap { $0.element }
}
}
extension Reactive where Base: AWSMobileClient {
func signIn(username: String, password: String) -> Observable<SignInResult> {
return Observable.create { observer in
self.base.signIn(username: username, password: password) { (signinResult, error) in
if let signinResult = signinResult {
observer.onNext(signinResult)
observer.onCompleted()
} else {
observer.onError(error ?? RxError.unknown)
}
}
return Disposables.create()
}
}
func confirmForgotPassword(username: String, newPassword: String, confirmationCode: String) -> Observable<ForgotPasswordResult> {
return Observable.create { observer in
self.base.confirmForgotPassword(username: username, newPassword: newPassword, confirmationCode: confirmationCode) { (confirmForgotPasswordResult, error) in
if let confirmForgotPasswordResult = confirmForgotPasswordResult {
observer.onNext(confirmForgotPasswordResult)
observer.onCompleted()
} else {
observer.onError(error ?? RxError.unknown)
}
}
return Disposables.create()
}
}
}
The segue should only be triggered after a successful password update, the password updates successful which is confirmed by a print statement.
I'm going to guess that showAlert presents a UIAlertController, which is a kind of UIViewController...
If my guess is correct, then your problem is with these lines:
self.showAlert(title: PasswordUpated.title, message: "")
self.transitionToLogin()
You are trying to present two view controllers at the same time. You need to wait until the alert is finished presenting before attempting to present the next view controller, or more likely wait until the alert is finished being dismissed.
(This is not an RxSwift question.)

Swift window hierarchy error when I try to login or sign up in my app?

I have question about window hierarchy. When I try to login or sign up and open the home page of app, I can't present other pages console error give that:
Warning: Attempt to present on whose view is not in the window hierarchy!
But when I re-open my app with same user everything working correctly. Here the code which is after create user process:
func createUser(withEmail email: String, password: String, username: String) {
Auth.auth().createUser(withEmail: email, password: password) { (result, error) in
if let error = error {
print("Failed to sign user up with error: ", error.localizedDescription)
return
}
guard let uid = result?.user.uid else { return }
let values = ["E-mail": email, "Kullanıcı Adı": username]
Database.database().reference().child("users").child(uid).updateChildValues(values, withCompletionBlock: { (error, ref) in
if let error = error {
print("Failed to update database values with error: ", error.localizedDescription)
return
}
let layout = UICollectionViewFlowLayout()
let homeController = HomeController(collectionViewLayout: layout)
let navController = UINavigationController(rootViewController: homeController)
self.present(navController, animated: false, completion: nil)
})
}
}
here the function which call top function:
#objc func handleSignUp() {
guard let email = emailTextField.text else { return }
guard let password = passwordTextField.text else { return }
guard let username = usernameTextField.text else { return }
createUser(withEmail: email, password: password, username: username)
}
Maybe your rootViewController is presenting another ViewController.
You can try :
if let presentedVC = self.presentedViewController {
presentedVC.present(navController, animated: false, completion: nil)
} else {
self.present(navController, animated: false, completion: nil)
}

rootViewController not loading after calling it, using -> present(viewControllerToPresent: UIViewController, animated: true, completion: nil)

My rootViewController works and loads fine. However, when I call it using the present(viewControllerToPresent: UIViewController, animated: true, completion: nil) from another viewController I get nothing but a black screen.
I looked all over the stackOverflow but only found solutions for storyboard users. I am doing this programmatically
#objc func handleLogin() {
print("LOGIN BUTTON TOUCHED")
guard let email = emailTextField.text, let password = passwordTextField.text else {
print("Form is not valid.")
return
}
Auth.auth().signIn(withEmail: email, password: password) { (user, error) in
if error != nil {
print(error!)
return
}
let viewController = RootViewController()
*** self.present(viewController, animated: true, completion: nil)
print("Logged in")
}
}
There is nothing wrong with self.present(viewController, animated: true, completion: nil)
I think your RootViewController() is already presented. The black screen you see is might be the one without any data? I am not sure, will need your code for that class.
Another approach you can consider is to replace the real rootViewController from current uiWindow like this
#objc func handleLogin() {
print("LOGIN BUTTON TOUCHED")
guard let email = emailTextField.text, let password = passwordTextField.text else {
print("Form is not valid.")
return
}
Auth.auth().signIn(withEmail: email, password: password) { [weak self] (user, error) in
guard let strongSelf = self else { return }
guard error == nil else { return }
guard let user = user else { return }
UIApplication.shared.keyWindow?.rootViewController = RootViewController()
print("Logged in")
}
}
you've created a new instance(RootViewController) and it must be black .. your not referring to your RootViewController

Facebook LoginManager Callback/PrepareforSegue Swift

I'm trying to pass a property to my next VC using prepareforSegue. It is called, however my other VC does not load.
Original
#IBAction func onSignupPressed(sender: AnyObject) {
FBSDKLoginManager().logInWithReadPermissions(permissions,
fromViewController: self) { result, error in
guard error == nil else { print("Login Error"); return }
guard result.grantedPermissions.contains("email") else {
print("No Email Permissions"); return }
self.getFBUserData()
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("loginSegue", sender: self)
}
}
}
I've been able to get the next VC showing by doing calling my doLogin function below. And there I instantiate a VC from the storyboard and present it. I believe it is due to the timing of the Facebook login window that pops up and closes. I searched for a delegate method, but have not found anything
#IBAction func onSignupPressed(sender: AnyObject) {
FBSDKLoginManager().logInWithReadPermissions(permissions,
fromViewController: self) { result, error in
guard error == nil else { print("Login Error"); return }
guard result.grantedPermissions.contains("email") else {
print("No Email Permissions"); return }
self.getFBUserData()
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("loginSegue", sender: self)
}
}
}
func getFBUserData(){
let params = "id, name, first_name, last_name, picture.type(large),friends, email, birthday, work, photos, education, location, hometown, religion, likes, about"
if((FBSDKAccessToken.currentAccessToken()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields":params]).startWithCompletionHandler({ (connection, result, error) -> Void in
if (error == nil){
//everything works print the user data
print(result)
let resultdict = result as? NSDictionary
self.user = Mapper<User>().map(result)
self.doLogin()
}
})
}
}
func doLogin() {
let successVC = self.storyboard?.instantiateViewControllerWithIdentifier("LoginSucessViewController")
self.presentViewController(successVC!, animated: true, completion: nil)
}
Very silly mistake! Didn't realize I could simply set the property of instantiating the VC!
func doLogin() {
let successVC = self.storyboard?.instantiateViewControllerWithIdentifier("LoginSucessViewController") as! LoginSucessViewController
successVC.currentUser = user
self.presentViewController(successVC, animated: true, completion: nil)
}

Swift GameCenter not behaving properly

I have 2 problems I am experiencing with GameCenter.
If a player is not signed into GameCenter, after if gives you the alert saying you are not signed in, I am no longer able to click any buttons I have on my view.
If a player is signed into GameCenter, after accessing the Leaderboards, pressing “done” will not dismiss the leaderboard view.
Here is my code that relates to GameCenter:
GameViewController:
func authPlayer() { // Gets called in ViewDidLoad
let localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {
(view, error) in
if view != nil {
self.presentViewController(view!, animated: true, completion: nil)
}
else {
print(GKLocalPlayer.localPlayer().authenticated)
}
}
}
GameScene:
if gameCenterBtn.containsPoint(location) { // In touches began for touch in touches
saveHighScore(highLevel)
let viewController = self.view!.window?.rootViewController
let gcvc = GKGameCenterViewController()
viewController?.presentViewController(gcvc, animated: true, completion: nil)
}
func saveHighScore(number : Int) {
if GKLocalPlayer.localPlayer().authenticated {
let scoreReporter = GKScore(leaderboardIdentifier: "myLeaderBoardID")
scoreReporter.value = Int64(number)
let scoreArray : [GKScore] = [scoreReporter]
GKScore.reportScores(scoreArray, withCompletionHandler: nil)
}
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController) {
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
Any and all help would be appreciated
1) Not sure this will help, but your login code is not quite correct. If there is no login view controller doesnt necessarily mean the player is signed in. You are also not handling the optional error. Try this instead.
localPlayer.authenticateHandler = { [unowned self] (viewController, error) in // will handle login changes also
if let error = error {
print(error.localizedDescription)
return
}
if let viewController = viewController {
self.presentViewController(viewController, animated: true, completion: nil)
}
else if self.localPlayer.authenticated {
print("Player authenticated")
}
else {
print("Player not authenticated")
}
}
I am not sure why your gameViewCntroller will not respond. Are you not just loading the first SKScene in your gameViewController.
Could you describe further, maybe with some code, of what does not work afterwards.
2) Its not dismissing the screen because you did not set the delegate.
You code where you are creating the Game Center viewController should look like this
let viewController = self.view?.window?.rootViewController
let gcvc = GKGameCenterViewController()
gcvc.gameCenterDelegate = self // YOU FORGOT THIS LINE
viewController?.presentViewController(gcvc, animated: true, completion: nil)

Resources