Did u ever wonder, how the program starts? Where is the entry point and how compiler know that he should start from this point? The answer is simple - the entry point is where the first instruction of the program and where the program has access to command-line arguments.

In simple case entry point is the very first address with some instruction. In a more complex system, this may be inside some runtime library or at some known memory address.

Alternative option - use a named point for an entry point. Named point - is just a name defined by programming language.

If we switch to iOS development, thus most part use C-family languages under the hood, an entry point for us has the name main.

Other languages also have similar entry points - in Java entry point also main, in C# Main.

Let’s inspect the iOS app entry point when using different languages and approaches.

Objective-C

When we create the iOS app and select the primary language like Objective-C, then u can easily find entry point in the project by checking file main.m:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
  • int argc - count of arguments
  • char * argv[] - list of arguments itself if u run program like $ myapp hello, u will receive argc equal to 2 and in argv something like:
/Users/kyryl.horbushko/Desktop/myapp
hello

That’s it. As u can see - the result of the main function is a call to UIApplicationMain function call.

This function takes input arguments and the name of the app delegate and instantiates the application object.

Here we pass nil. for it - so default UIApplication object one will be used

Another responsibility of this function is to set up the main event loop, including the application’s run loop, and processing events. It also checks metadata and displays UI if it’s applicable. This makes the app be alive.

It’s also good to know that this function never returns, thus it has return type Int. So while this function executed - u’r app alive, even in the background.

U can also notice that inside there is an autoreleasepool. The autoreleasepool is a mechanism that allows the system to efficiently manage the memory your application uses as it creates new objects. source

The simplest version (for console app) of the main function may be as follow:

int main (int argc, const char * argv[]) {
    @autoreleasepool {
       NSLog (@"Hello");
    }
    return 0;
}

Thus iOS app uses a specific place to run and has additional configurations to be done, UIApplicationMain used in addition.

Swift

Create a new Swift project and try to find main function, even no main.m file:

swift-nomain


U can add symbolic breakpoint main and the app will be paused on the main function. Then use the bt command:

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
  * frame #0: 0x0000000100cd82f0 main-Swift`main at main.swift:0
(lldb) 

As u can see - there is at frame #0 call to function main

Instead, u can observe the @UIApplicationMain or even the @main attribute at a class.

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

if use Swift 5.3:

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

@UIApplicationMain

When u use an attribute on some class @UIApplicationMain u simply told the compiler which class he should use as a parameter to the same old UIApplicationMain function that he will synthesize in runtime.

in compiler source there is a define SWIFT_ENTRY_POINT_FUNCTION "main" source

/// The symbol name used for the program entry point function.
#define SWIFT_ENTRY_POINT_FUNCTION "main"

U may remove this attribute and u’r app will terminate as soon as u run it - that’s because the main function completes execution and UIApplicationMain is not executed and so no object is created.

with older versions of Swift u may receive an error Undefined symbols _main. I tested on iOS 14 - and looks like the compiler just generate an empty main function

To check that this attribute works exactly as we think, we may try to replace the @UIApplicationMain attribute with a concrete implementation of the UIApplicationMain function. To do so we may define required input parameters in the file - a subclass of UIApplication, UIApplicationDelegate, and CommandLine args.

int UIApplicationMain(int argc, char * _Nullable *argv, NSString *principalClassName, NSString *delegateClassName);

Then we should create a separate file main.swift and add a function in it:

import UIKit

UIApplicationMain(
  CommandLine.argc,
  CommandLine.unsafeArgv,
  NSStringFromClass(MyApplication.self),
  NSStringFromClass(AppDelegate.self)
)

If u wonder why we should put the code in a separate main.swift file, here is the perfect explanation:

Application Entry Points and “main.swift” You’ll notice that earlier we said top-level code isn’t allowed in most of your app’s source files. The exception is a special file named “main.swift”, which behaves much like a playground file, but is built with your app’s source code. The “main.swift” file can contain top-level code, and the order-dependent rules apply as well. In effect, the first line of code to run in “main.swift” is implicitly defined as the main entry point for the program. This allows the minimal Swift program to be a single line — as long as that line is in “main.swift”.

In Xcode, Mac templates default to including a “main.swift” file, but for iOS apps the default for new iOS project templates is to add @UIApplicationMain to a regular Swift file. This causes the compiler to synthesize a main entry point for your iOS app, and eliminates the need for a “main.swift” file.

Alternatively, you can link in the implementation of main written in Objective-C, common when incrementally migrating projects from Objective-C to Swift. source

Now, we can run and our app without the attribute @UIApplicationMain.

in Cocoa similar attribute called @NSApplicationMain

@main

With Swift 5.3 we got new attribute @main - Type-Based Program Entry Points.

From the official doc, this attribute may be applied to a structure, class, or enumeration declaration to indicate that it contains the top-level entry point for program flow. source

The purpose of this attribute is to remove hardcoded attributes for iOS and macOS and instead make code more generic and thus simpler.

As mention in this proposal - “When the program starts, the static main() method is called on the type marked with @main. “.

With @main attribute we also have a few options:

  • a single, non-generic type designated with the @main attribute
  • a single main.swift file

So using this, we can define next:

class MyStartingPoint: EntryPointProvidable { }

protocol EntryPointProvidable { }

extension EntryPointProvidable {
    static func main() {
        print("hello")
    }
}

and in main.swift:

MyStartingPoint.main()

As expected, u will see print message, but the app will end as soon as it prints it. why? same reason as before - this function didn’t initialize an object responsible for the lifecycle of the app, event handling, UI, etc.

If u would like to use your own entry point, u still need to use function UIApplicationMain:

UIApplicationMain(
    CommandLine.argc,
    CommandLine.unsafeArgv,
    nil,
    NSStringFromClass(AppDelegate.self)
)

As result - the @main attribute just simplifies a bit our life, reducing the amount of code that needs to be written in case if we still conform to UIKit protocol UIApplicationDelegate. We receive main, simply because of this:

extension UIApplicationDelegate {

    public static func main()
}

So, the purpose of the @main attribute is to allow frameworks to easily define custom entry point behavior without additional language features. An example may be library from Apple

A main.swift file is always considered to be an entry point, even if it has no top-level code. Because of this, placing the @main-designated type in a main.swift file is an error.

download test sources

Resource