VC1 is my homepage in the project and I can go to 5 different view controllers from VC1. In VC1 viewDidLoad I am downloading data from my Firestore database and I need them all to be loaded to the phone before allowing the user to interact with the buttons in the navigation bar. Here is how my VC1 look like (3 buttons bottom, 2 buttons top):
But currently user can click a button in VC1 while the data from viewDidLoad is not fully loaded to the phone and gets them to go from VC1 to VC2 (if they are fast enough, they can accomplish this).
How can I prevent a user to interact with the buttons in the nav bar unless all the functions in the viewDidLoad is completed?
override func viewDidLoad() {
super.viewDidLoad()
func1()
func2()
func3()
}
Not sure if this is related but in my AppDelegate this is how I define my rootViewController:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
let storyboard = UIStoryboard(name: "Main", bundle: .main)
window?.rootViewController = storyboard.instantiateViewController(withIdentifier: "TabBarController")
}
And this is what I have in main Storyboard:
and this is my home storyboard:
The user cannot touch any button while viewDidLoad
is running. Or to be more precise: The buttons will not react upon events while those viewDid...
, viewWill...
functions are running. This is because all those methods are executed in the main thread and will block any user interaction.
I assume your "problem" is caused because func1()
, 2 or 3 are calling network services, which typically run in a arbitrary worker thread. Therefore, func1
returns before all data has been fetched, therefore also viewDidLoad
returns too early for you.
Since you should never run the network calls in the main thread (and Firestore calls won't do so either), you need to do some extra work, for example:
viewDidLoad
, disable all buttons you don't want the user to interact withDispatchQueue.main.async
for this)DispatchGroup