Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run Code Before First View Controller is Initialized (Storyboard-based App)

My app needs to perform some cleanup tasks -delete old data stored locally- every time on startup, before the initial view controller is displayed.

This is because that initial view controller loads the existing data when initialized, and displays it inside a table view.

I set up several breakpoints and found out that the initial view controller's initializer (init?(coder aDecoder: NSCoder)) is run before application(_:didFinishLaunchingWithOptions) - even before application(_:**will**FinishLaunchingWithOptions), to be precise.

I could place the cleanup code at the very top of the view controller's initializer, but I want to decouple the cleanup logic from any particular screen. That view controller may end up not being the initial view controller one day.

Overriding the app delegate's init() method and putting my cleanup code there does get the job done, but...

Question:

Isn't there a better / more elegant way?


Note: For reference, the execution order of the relevant methods is as follows:

  1. AppDelegate.init()
  2. ViewController.init()
  3. AppDelegate.application(_:willFinishLaunchingWithOptions:)
  4. AppDelegate.application(_:didFinishLaunchingWithOptions:)
  5. ViewController.viewDidLoad()

Clarification:

The cleanup task is not lengthy and does not need to run asynchronously: on the contrary, I'd prefer if my initial view controller isn't even instantiated until it completes (I am aware that the system will kill my app if it takes to long to launch. However, it's just deleting some local files, no big deal.).

I am asking this question mainly because, before the days of storyboards, app launch code looked like this:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];

    // INITIAL VIEW CONTROLLER GETS INSTANTIATED HERE 
    // (NOT BEFORE):
    MyViewController* controller = [[MyViewController alloc] init];

    self.window.rootViewController = controller;

    [self.window makeKeyAndVisible];
    return YES;
}

...but now, because main storyboard loading happens behind the scenes, the view controller is initialized before any of the app delegate methods run.

I am not looking for a solution that requires to add custom code to my initial view controller.

like image 640
Nicolas Miari Avatar asked Jan 28 '16 06:01

Nicolas Miari


People also ask

How do I change the initial view controller in storyboard?

Specifying the Initial View Controller storyboard and select the Tab Bar Controller Scene. On the right, select the Attribute inspector. You'll find a checkbox named Is Initial View Controller. Checking this box will identify the selected view controller as the initial entry point for the storyboard you're on.


1 Answers

I am not sure if there is more elegant way but there are definitely some other ways...

I'd prefer if my initial view controller isn't even instantiated until it completes

This is not a problem. All you have to do is to delete a UIMainStoryboardFile or NSMainNibFile key from the Info.plist which tells the UIApplicationMain what UI should be loaded. Subsequently you run your "cleanup logic" in the AppDelegate and once you are done you initiate the UI yourself as you already shown in the example.

Alternative solution would be to create a subclass of UIApplicationMain and run the cleanup in there before the UI is loaded.

Please see App Life Cycle below:

iOS App Life Cycle

like image 80
0101 Avatar answered Sep 24 '22 06:09

0101