pushViewController for once - swift

I have one UIButton which called Get Started in the welcome screen, by clicking on this button it will goes to the PhoneNumberViewController to type and click on the next button. For new users it will require to fill out some personal information in the ProfileViewController before going to the HomeViewController. Now I am struggling how can I pop that profile for once since I do not need registered users to check their information when they logout and re-login later.
Here is my code :
private func checkUser(userId: String) {
userService.getUser(Uid: userId) { (tutor) in
if let user = user,
!user.name.isEmpty && !user.email.isEmpty {
Router.route(to: .home)
} else {
let profileViewController = UIStoryboard.main.viewController(of: ProfileViewController.self)
profileViewController.isFromOnboarding = true
self.navigationController?.pushViewController(profileViewController, animated: true)
}
}
}

You can save a value in userDefault
private func checkUser(userId: String) {
let isPresented = UserDefaults.standard.bool(forKey: "isPresented")
userService.getUser(Uid: userId) { (tutor) in
if let user = user,
!user.name.isEmpty && !user.email.isEmpty {
Router.route(to: .home)
} else if !isPresented {
UserDefaults.standard.set(true, forKey: "isPresented")
let profileViewController = UIStoryboard.main.viewController(of: ProfileViewController.self)
profileViewController.isFromOnboarding = true
self.navigationController?.pushViewController(profileViewController, animated: true)
}
}
}

Create a hasPushedProfile flag in the controller which can be used to check if the profile view has already been shown or not. On the first time through the flag will be false and will then be set to be true when the profile is displayed, next time through the profile will not display and you can do something else instead.
import UIKit
class LoginController: UIViewController {
static var hasPushedProfile = false
private func checkUser(userId: String) {
userService.getUser(Uid: userId) { (tutor) in
if let user = user,
!user.name.isEmpty && !user.email.isEmpty {
Router.route(to: .home)
} else {
if hasPushedProfile == false {
hasPushedProfile = true
let profileViewController = UIStoryboard.main.viewController(of: ProfileViewController.self)
profileViewController.isFromOnboarding = true
self.navigationController?.pushViewController(profileViewController, animated: true)
} else {
// Already pushed profile, do something else...
}
}
}
}
}

Related

NSUserActivity deleteAllSavedUserActivities not working

My case is utterly simple: I use the next function
private func launchActivity(_ id: String, title: String, invocPhrase: String) {
userActivity = NSUserActivity(activityType: "Open_bank")
userActivity?.title = title
userActivity?.userInfo = ["id": id]
if #available(iOS 12.0, *) {
userActivity?.suggestedInvocationPhrase = invocPhrase
userActivity?.isEligibleForPrediction = true
userActivity?.persistentIdentifier = id
} else {
//Can't actually invoke this block
}
}
to create a certain userActivity, and then add it to Siri, so that it can be invoked by by invocPhrase. Here is the function which does this.
func presentAddOpenBankToSiriVC() {
guard let userActivity = self.userActivity else { return }
if #available(iOS 12.0, *) {
let shortcut = INShortcut(userActivity: userActivity)
let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut)
viewController.modalPresentationStyle = .formSheet
viewController.delegate = self
present(viewController, animated: true, completion: nil)
} else {
//Can't actually invoke this block
}
}
Later I try to delete it (as well as all other user activities)
NSUserActivity.deleteAllSavedUserActivities {}
And it just does not delete any user activity, contrary to what's written in Apple Documentation
https://developer.apple.com/documentation/sirikit/deleting_donated_shortcuts
Actually, at first, I've tried a method
deleteSavedUserActivities(withPersistentIdentifiers:completionHandler:)
with userActivity's persistentIdentifier, but, obviously, also to no avail.
I've no idea why it refuses to budge but would be grateful to any help or hint

Firebase Login Persistence Swift

I'm using Firebase to handle my user register and login for my app. But if I log in, and then close my app entirely - the user is forced to re-log in. I'd like to keep the user logged in unless they click "Log out"
My login code is this:
Auth.auth().signIn(withEmail: email, password: password, completion: {(user, error) in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
}
self.presentTabBar()
})
}
}
How do I keep this user logged in unless specifically told to logout?
Here's a handy full example for 2020:
Anywhere in your iOS+Firebase app, you can simply say:
guard let uid = Auth.auth().currentUser?.uid else {
return print("no current user!")
}
Thus, on the launch screen of your app, simply:
import UIKit
import Firebase
import FirebaseUI
class ViewController: UIViewController, FUIAuthDelegate {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let uid = Auth.auth().currentUser?.uid else {
return print("no current user, hence AuthUI flow...")
basicAuthUIFlow()
}
print("User .. \(Auth.auth().currentUser?.displayName)")
continueWhenUserPresent()
}
It's that easy. So then as usual ...
private func basicAuthUIFlow() {
let authUI = FUIAuth.defaultAuthUI()
authUI?.delegate = self
let pp: [FUIAuthProvider] = [ FUIGoogleAuth() ]
authUI?.providers = pp
if let authVC = authUI?.authViewController() {
present(authVC, animated: true)
}
}
func authUI(_ authUI: FUIAuth,
didSignInWith authDataResult: AuthDataResult?,url: URL?, error: Error?) {
let u = authDataResult?.user
print("Successful login via authUI \(String(describing: u?.displayName))")
continueWhenUserPresent()
}
private func continueWhenUserPresent() {
.. pushViewController .. your first screen
}
Check if the user is logged in or not:
if Auth.auth().currentUser != nil {
// User is signed in.
// ...
} else {
// No user is signed in.
// ...
}
if the user is logged in, then go the Home ViewController. This way when he opens the app again he will go to the Home ViewController unless he sign outsFIRAuth.auth().signOut()
For more info check this: https://firebase.google.com/docs/auth/ios/manage-users
For keep user login you need to check currentUser Auth session, If it's not nil then you can redirect user to Home screen.
Call "setRootViewController" method from didFinishLaunchingWithOptions, just after FirebaseApp.configure() code
Swift 4
func setRootViewController() {
if Auth.auth().currentUser != nil {
// Set Your home view controller Here as root View Controller
self.presentTabBar()
} else {
// Set you login view controller here as root view controller
}
}

NSKeyedUnarchiver.unarchiveObject() unarchives old object

I want to save the user's filter selections on FilterViewController.
When FilterViewController is closed, NSKeyedArchiver.archiveRootObject archives the user's selections. However, NSKeyedUnarchiver.unarchiveObject opens up the initial default selections (NOT the user's selections). How to fix this?
FiltersViewController.swift
override func viewWillAppear(_ animated: Bool) {
if let filterSections = NSKeyedUnarchiver.unarchiveObject(withFile: filterViewModel.filtersFilePath) as? [FilterSection] {
// Retrieves initial default selections, NOT user's selection
filterViewModel.filterSections = filterSections
filtersTableView.reloadData()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Saves what user selects
let isSuccessful = NSKeyedArchiver.archiveRootObject(self.filterViewModel.filterSections, toFile: self.filterViewModel.filtersFilePath)
if (isSuccessful) {
print("Saved filters") // This is printed
} else {
print("Didn't Save filters")
}
}
FilterViewModel.swift
class FilterViewModel: NSObject {
// Contains all filtered sections displayed on table view
var filterSections: [FilterSection] = []
// File Path to saved Filter Sections
var filtersFilePath: String {
let manager = FileManager.default
let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
print("this is the url path in the documentDirectory \(url)")
return (url!.appendingPathComponent("FilterSelectionData").path)
}
override init() {
super.init()
filterSections = self.getFilterSections()
}
}
CompanyViewController.swift
#objc func filterButtonTapped() {
var filterViewModel: FilterViewModel
if (self.filterViewModel != nil) {
filterViewModel = self.filterViewModel! // This runs
}
else {
self.filterViewModel = FilterViewModel()
filterViewModel = self.filterViewModel!
}
let filtersVC = FiltersViewController(filterViewModel: filterViewModel)
self.navigationController?.pushViewController(filtersVC, animated: true)
}
You are using self.getFilterSections to set filterSections in FilterViewModel init. I suppose self.getFilterSections is a method that returns the default values. For me, it should not be the case, rather if you have archived some values, you should get that in this method. Although, this alone should not be the reason for the issue, but may be a reason for inducing bug. Try changing self.getFilterSections to return archived values if possible otherwise default values and check whether the bug is still there.

Show View Controller based on the users Firebase login state

In my app I want do display different ViewControllers depending on if the user is already logged in or not. Like if the user is logged in present VC_A if not, present VC_B. I tried the following code in my vc_login:
if let user = FIRAuth.auth()?.currentUser {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "vc_home") as! ViewController_Home
self.present(vc, animated: true, completion: nil)
} else {
// Do Nothing
}
You can do it like that (hints are in the code comments):
if FIRAuth.auth()?.currentUser?.uid == nil {
// user is not logged in
// present VC_B
} else {
// user is logged in
// present VC_A
}
Or you can use the ternary conditional operator like this:
FIRAuth.auth()?.currentUser?.uid == nil ? presentViewControllerB() : presentViewControllerA()
func presentViewControllerA() {
// call if logged in
}
func presentViewControllerB() {
// call if not logged in
}

Remove/Hide UITabBarItem in Swift

I have looked really hard for this solution in Swift but am not coming up with one that works for me. I am trying to hide my "Admin" TabBarItem based on the permissions of the person that logs in to the app. I can disable it but it still shows up on the bar. I want to be able to show it for certain people and hide it for others. Also, when I print self.tabBarController?.viewControllers I get nil.
class TabBarMenuController: UITabBarController {
let ref = Firebase(url: "")
var position = ""
func getPosition() {
let userRef = ref.childByAppendingPath("users/\(ref.authData.uid)")
userRef.observeSingleEventOfType(.Value, withBlock: {snapshot in
if snapshot.value["position"] as! String != "Staff" {
self.position = snapshot.value["position"] as! String
}
})
}
override func viewWillAppear(animated: Bool) {
getPosition()
print(self.tabBarController?.viewControllers)
if position != "Staff" {
if let tabBarController = self.tabBarController {
let indexToRemove = 3
if indexToRemove < tabBarController.viewControllers?.count {
var viewControllers = tabBarController.viewControllers
viewControllers?.removeAtIndex(indexToRemove)
tabBarController.setViewControllers(viewControllers, animated: true)
}
}
}
}
Also, I keep reading that this is against Apple's intended use. Is that true still? Is there a better workflow to accomplish that type of functionality?
I would create a tab that opens up the user's account and have a button in the user VC tab that opens up a page for admins only. you can show and hide the button as needed using adminButton.hidden = true or adminButton.hidden = false.