If I have a class and initialize a variable like so:
class TestClass: UIViewController {
var thisInt: Int = 10
}
is that any different than initializing like so:
class TestClass: UIViewController {
var thisInt: Int!
override func viewDidLoad() {
super.viewDidLoad()
thisInt = 10
}
}
I suppose my main questions lie in when the global initialization takes place, and is there a time when one would get called more than the other would be called with normal iOS Programming (not doing anything drastically against native development). I do understand that doing it in viewDidLoad restricts me to using weak or an optional, but I'm more concerned about any other differences.
You can find out easily by adding a "computed" property to your view controller:
class TestClass: UIViewController {
let a = {()->Int in print("global initialization"); return 10 }()
}
and adding a
print("didFinishLaunching")
in app's delegate didFinishLaunchingWithOptions
method.
The order you'll get is
global initialization
didFinishLaunching
which means global initializers run before the app lifecycle begins.
Now, to go even further, you could add a main.swift
file with the following contents
print("Before UIApplicationMain")
UIApplicationMain(CommandLine.argc, unsafeBitCast(CommandLine.unsafeArgv, to: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>.self), nil, NSStringFromClass(AppDelegate.self))
and remove (or comment) the @UIApplicationMain
decoration from your AppDelegate class. This will instruct the compiler to use the code in main.swift
for the application initialization instead of the default behavior provided by the decorator in discussion (although we're providing a custom almost identical implementation).
What you'll get in this 2nd approach is
Before UIApplicationMain
global initialization
didFinishLaunching
which means that the instance property code is executed when the storyboard is loaded.
Now, for more insight, let's try to find out the differences between static an instance variables. For this we'll add a test class:
class PropertyInitializationTest {
static let staticProp = {()->String in print("static initialization of InitializationTest"); return "" }()
let instanceProp = {()->String in print("instance initialization of InitializationTest"); return "" }()
init() {
print("In initializer")
}
}
, and update AppDelegate's did finish launching:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print("didFinishLaunching")
print("before instantiating InitializationTest")
_ = PropertyInitializationTest()
print("after instantiating InitializationTest")
// Override point for customization after application launch.
return true
}
The output we get is:
Before UIApplicationMain
global initialization
didFinishLaunching
before instantiating InitializationTest
instance initialization of InitializationTest
In initializer
after instantiating InitializationTest
, which confirms the fact that instance properties get set when the class is instantiated, and before any initializer code runs.
But wait! What about the static property? There are no traces to indicate that it was initialized at all. Looks like static properties are lazy by definition, and get initialized only when accessed the first time.
Updating the app did finish launching code confirms this.
print("didFinishLaunching")
print("before instantiating InitializationTest")
_ = PropertyInitializationTest()
print("after instantiating InitializationTest")
_ = PropertyInitializationTest.staticProp
print("after instantiating InitializationTest")
gives the following output:
Before UIApplicationMain
global initialization
didFinishLaunching
before instantiating InitializationTest
instance initialization of InitializationTest
In initializer
after instantiating InitializationTest
static initialization of InitializationTest
after instantiating InitializationTest
To conclude: