SoFunction
Updated on 2025-04-12

Detailed explanation of the startup process of iOS app

Key Steps
A program starts from the main function.

Copy the codeThe code is as follows:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

You can see that the main function will call the UIApplicationMain function, and its four parameters mean:
  • argc: represents the number of parameters of the program when entering the main function. The default is 1.
  • argv: represents the various parameters included. Default is the name of the program.
  • principalClassName: The name of UIApplication or its subclass. If the passed nil, it represents the name of UIApplication, that is, @"UIApplication".
  • delegateClassName: The name of the proxy of UIApplication.

In the UIApplicationMain function, based on the incoming UIApplication name and its proxy name, the following will be mainly done:

  • Create a UIApplication object based on the incoming name.
  • Create a UIApplication proxy object based on the incoming proxy name.
  • Turn on the event loop (if the loop is not performed, the program will end after the main function is finished. Make sure that the program can exist all the time after the program is created).
  • Parsing the file:

The file will be searched for whether the value corresponding to the Main storyboard file base name Key has a value. If there is a value, it means that the controller will be loaded through the Storyboard later. AppDelegate will receive the didFinishLaunchingWithOptions message (when the program starts up, it will be completed). At this time, Storyboard will perform a series of loading operations (more on the next step); if there is no value, the controller will not be loaded through the Storyboard. Then AppDelegate will receive the didFinishLaunchingWithOptions message (when the program starts up), and at this time we need to load the controller through code.

Note that the Main storyboard file base name Key is not a real key, but is written by Apple in order to enhance readability. The real key is UIMainStoryboardFile (can be viewed through the source code of the file).
This is why you need to set the Main Interface to blank when you want to create a controller in code instead of Storyboard, so that you will know that you do not create a controller through Storyboard when parsing the file.
From this we can see that the operation of parsing files mainly depends on whether we use the Storyboard method to load or the code method to load. The default Main storyboard file base name is Main, that is, the controller is loaded through the Storyboard method.
Now let’s analyze it in detail, load the controller through Storyboard and code.

By Storyboard
Through Storyboard, we mainly do the following things (we don’t need to do these things, they are automatically completed by the system and when the program starts and completes):

Create a window.

Create an instance of UIWindow to display the interface.

Set the root controller of the window.

Create a controller according to Storyboard settings.
And set this controller to the root controller of the window created previously.
Display the window. (Equivalent to makeKeyAndVisible mentioned later)

Sets the visible and sets the keyWindow of UIApplication.

In this step, add the view of the root controller to the window.

Through code
Through the code, we need to perform related operations on loading the controller in the didFinishLaunchingWithOptions method.

Copy the codeThe code is as follows:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    UIViewController *viewController = [[UIViewController alloc] init];
    = viewController;
// The view of the root controller has not been added yet
    [ makeKeyAndVisible];
// At this time, the view of the root controller is added
    return YES;
}


In fact, what is done here is the same as what the system does. (Equivalent to a systematic approach)

First create a window and get a correct UIWindow instance object to display the interface. (It is a property that comes with the system)

Then set the root controller of the window.

It is no longer loaded according to the settings in the Storyboard, and we need to create the controller ourselves at this time.
Set this controller to the root controller.
Note that the view of the root controller has not been added at this time. When the window is about to be displayed, the view of the root controller of the window will be added to the window. (You can output to verify)
Display the window.

Copy the codeThe code is as follows:

[ makeKeyAndVisible] actually does the following:

First, set it to UIApplication's keyWindow. This is to facilitate us to see which main window of UIApplication is in the future.

Next, let the visible code equivalent to executing is:

Copy the codeThe code is as follows:

= NO;

The reason for this is that the default hidden = YES, so it needs to be displayed.

So since makeKeyAndVisible performs the above operation, and in fact, replace [ makeKeyAndVisible] with = NO, the interface will also be displayed normally, because this is what makesKeyAndVisible does inside. However, the keyWindow of UIApplication is not set at this time. For the sake of easy access in the future, it is better to use makeKeyAndVisible.

After this step, the interface will be displayed, and the view of the root controller will be added to the above for normal display.

Here is one thing to note:

The AppDelegate created by the system comes with a property located in the .h file:

Copy the codeThe code is as follows:

@property (strong, nonatomic) UIWindow *window;

When loading the controller in Storyboard, when the application startup is completed (didFinishLaunchingWithOptions), an instance of UIWindow is needed to display the interface, so Apple provides this window property. The system automatically creates a window based on storyboard, and then assigns the window to this window property to ensure the work after completion.

When loading the controller in code, the same way, first of all, an instance of UIWindow is needed to display the interface. Because we do not use Storyboard, we have to create the window ourselves this time. There are two ways to do this at this time. The first is to create a UIWindow object in the didFinishLaunchingWithOptions method:

Copy the codeThe code is as follows:

UIWindow *myWindow = [[UIWindow alloc] initWithFrame:...];

However, if you run the program in this way, you will find that the interface still cannot be displayed, because myWindow is a local variable at this time, and this variable will be destroyed after the didFinishLaunchingWithOptions method is executed. So a better way is to directly use the window properties provided by the system:
Copy the codeThe code is as follows:

= [[UIWindow alloc] initWithFrame:...];

The same is true in previous examples.

In addition, if you look closely, you will find that the modifier of this window property is strong, not weak. Think about it, I used weak to modify a control because this control will be added to a view. The subViews array of this view will have strong references to the control, so there is no problem with weak. In this case, because the window control will not be added to other views, that is, there are no other strong pointers pointing to this object, so the modifier needs to be set to strong when creating it to ensure that the created window will not be destroyed. (The modifier of the window attribute created by Apple is strong)

UIWindow Supplement
The window is hierarchical and can have multiple windows at the same time. For example: the status bar is a window, and the keyboard is also a window.

You can adjust the level by setting the windowLevel property of the UIWindow object.

= UIWindowLevelStatusBar;
There are three levels of window: UIWindowLevelNormal, UIWindowLevelStatusBar UIWindowLevelAlert. If three levels appear on the screen at the same time, then alert is at the top, statusBar is in the middle, and normal is at the bottom.

Note: If there are multiple windows in a program, the controller will hide the status bar by default.

Solution: Turn off the controller's control of the status bar (to add View controller-based status bar appearance key and set to NO) so that these windows and status bars can be displayed normally according to hierarchical relationships.

Overview
Here PY is the prefix:

1. Execute the main function first, and the UIApplicationMain function will be called internally.

What is done in the function:

(1) Create a UIApplication object

(2) Create a delegate object of UIApplication——PYAppDelegate

(3) Open a message loop: Every time the corresponding system event is heard, MJAppDelegate will be notified to be notified every time MJAppDelegate is heard

(4) Create a UIWindow object (inherited from UIView) for the application and set it to the window property of PYAppDelegate

(5) Load the file and read the name of the main storyboard file

(6) Load the main storyboard file and create the controller object pointed by the white arrow

(7) And set the controller created in step 6 to the rootViewController property of UIWindow (root controller)

(8) Display the UIWindow. Before displaying the view of the rootViewController will be added to the UIWindow (only in this step, the controller's view will be created)

Copy the codeThe code is as follows:

[window addSubview: ];

Enter the main function, and the UIApplicationMain method is executed in the main function. This is the entry point of the ios program!
Copy the codeThe code is as follows:

int UIApplicationMain(int argc, char argv[], NSString principalClassName, NSString *delegateClassName)

argc, argv: Parameters of ISO C standard main function, which can be directly passed to UIApplicationMain for related processing.

principalClassName: Specifies the application class, which must be a UIApplication (or subclass). If nil, use the UIApplication class as the default value

delegateClassName: Specifies the proxy class of the application class, which must comply with the UIApplicationDelegate protocol

This function will create a UIApplication object based on principalClassName, create a delegate object based on delegateClassName, and assign the delegate object to the delegate attribute in the UIApplication object.

lUIApplication object will send different messages to the delegate object in turn, and then the application's main runloop (event loop) will be established to process the event (firstly, the application of the delegate object:didFinishLaunchingWithOptions:)

This function will only return when the program exits normally. If the process is to be forced to be killed by the system, this function will usually terminate before it can return to the process.

Let’s have pictures and the truth!!!