Swift @main Entry Points

Mar 12, 2023#swift

The first thing you need to do with any new language is figure out how to get some code running. This post will help you learn different attributes —@UIApplicationMain, @NSApplicationMain, or @main— for designating a type as the entry point for beginning program execution.

Top-level code

The top-level code in a Swift source file consists of zero or more statements, declarations, and expressions. By default, variables, constants, and other named declarations that are declared at the top-level of a source file are accessible to code in every source file that’s part of the same module.

There are two kinds of top-level code:

  • Top-level declarations consist of only declarations, allowed in all Swift source files.
  • Executable top-level code contains statements and expressions, not just declarations, and is allowed only as the top-level entry point for the program.

The Swift code you compile to make an executable can contain at most one of the following approaches to mark the top-level entry point, regardless of how the code is organized into files and modules:

  • A file that contains top-level executable code
  • A main.swift file
  • The @main attribute
  • The @NSApplicationMain attribute
  • The @UIApplicationMain attribute

The compiler will ensure that the author of a program only specifies one entry point.

main.swift

First released in 2014, Swift was developed as a replacement for Apple’s earlier programming language Objective-C. Swift uses Clang internally to compile and provide interoperability with C/C++/Objective-C, so it’s natural that the starting point of its programs mimics it as well.

C/C++ program shall contain a global function named main(), which is the designated start of the program in hosted environment.

#include <iostream>
 
int main(int argc, char *argv[]) {
  std::cout << "argc == " << argc << '\n';
}

In Objective-C based apps, you call main() function in main.m file:

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

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

Swift programs start execution at the beginning of a file. This works great for procedural code, and allows simple Swift programs to be as short as a single line, with no special syntax required.

When having multiple files, you must designate one of them as the main one, the main file will be the entry point of the app and gain access to global expressions. In Swift, designating the main file is just a matter of naming it main.swift.

A main.swift file is always considered to be an entry point, even if it has no top-level code.

@main

Apply this attribute to a structure, class, or enumeration declaration to indicate that it contains the top-level entry point for program flow.

Types marked with @main have a single implicit requirement: declaring a static main() method. This main() method will typically be provided by libraries or frameworks, so that the author of a Swift program will only need to use the @main attribute to indicate the correct starting point.

// In a framework:
public protocol ApplicationRoot {
  // ...
}
extension ApplicationRoot {
  public static func main() {
    // ...
  }
}

// In MyProgram.swift:
@main 
struct MyProgram: ApplicationRoot {
  // ...
}

The main() method can be provided by the type itself, inherited from a superclass, or declared in an extension to a protocol the type conforms to. The main() method can either be declared as throws or not; errors thrown from a main() method will have the same behavior as errors thrown from top-level code.

@UIApplicationMain & @NSApplicationMain

Ever since its initial release, Swift has provided the synthesized platform-specific attributes @UIApplicationMain and @NSApplicationMain to smooth over this startup process for developers of UIKit and AppKit applications. I’ll only refer to @UIApplicationMain, the design for @NSApplicationMain follows the exact same pattern.

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  // ...
}

Apply @UIApplicationMain attribute to a class to indicate that it’s the application delegate. Using this attribute is equivalent to calling the UIApplicationMain(_:_:_:_:) function. If you don’t use this attribute, supply a main.swift file with code at the top level that calls the function as follows:

import UIKit

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

This function instantiates the application object from the principal class and instantiates the delegate (if any) from the given class and sets the delegate for the application. It also sets up the main event loop, including the application’s run loop, and begins processing events. If the application’s Info.plist file specifies a main nib file to be loaded, by including the NSMainNibFile key and a valid nib file name for the value, this function loads that nib file.

UIKit could add the static main() method to the UIApplicationDelegate, allowing authors to use the single @main attribute no matter the user interface framework, and allowing for the deprecation of @UIApplicationMain.

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
  // ...
}