Phase 1 and Phase 2 Initialization in Swift

Phase 1 and Phase 2 initialization in Swift

Given 2 classes Foo and Bar where Bar is a subclass of Foo:

class Foo {
var a: Int?
var b: Int?

init() {
a = 1
}
}

class Bar: Foo {
var c: Int?

override init() {
super.init() // Phase 1

// Phase 2: Additional customizations
b = 2
c = 3
}
}

When you call Bar() it calls super.init() which the first line is to initialize the superclass which is Foo. So once Foo's properties are initialized completely, they can be set in Foo's initializer. This is represented by the a = 1 in the Foo initializer.

Once that is complete, phase 2 begins which is continuing the initialization of Bar following the super.init() line. This is where you can "perform additional customizations" either on the instance of bar or on its superclass. This is represented by b = 2 and c = 3.

let x = Bar()
x.a // 1
x.b // 2
x.c // 3

Why two-phase initialization isn't working for the class in swift?

In a Swift class, a designated initializer can't call another designated initializer on itself. A designated initializer in a class can only call a designated initializer of its superclass (if there is one).

In a Swift class, a convenience initializer can only call a designated initializer on itself (not on a superclass if there is one).

These class rules come about due to class inheritance. The rules apply even if your class has no superclass. This is all covered in the Swift book under Class Inheritance and Initialization.

Your code as a class would work if you change the init(ft: Double, gallon: Double) initializer to a convenience initializer.

A Swift struct has slightly different rules since a struct doesn't support inheritance. A struct doesn't need to use convenience initializers which is why your original struct code worked. This is all covered in the Swift book under nitializer Delegation for Value Types.

The type of self in Swift and its use with respect to two-phase initialization

1)

Shouldn't I get a compiler error if I'm trying to use self too soon?

I do agree. You may send a bug report to swift.org.

Why does the compiler allow us to use self here if self is not ready to be used?

Unfortunately, there's another self in the descendants of NSObject, the method self() of NSObject.

2)

What is that and why does self have two different types within the same class?

The current Swift interprets the initial value expression in the class context, not in the instance context.

You know method names can be used as closures in Swift:

class ViewController: UIViewController {
//..

func aMethod() {
//...
}

func anInstanceMethod() {
let meth = aMethod // () -> ()
}
}

Swift can also refer to an instance method in the class context, which generates a so-called unapplied method reference (see SE-0042), which currently returns a curried function:

class ViewController: UIViewController {
//...

func aMethod() {
//...
}

class func aClassMethod() {
let meth = aMethod // (ViewController) -> () -> ()
}
}

The method self() as well.

Generally we do not need self() method and this behavior should be changed, I think.

Where to put super.init() when init() also initializes member variable and references self

You must initialize all non-optional properties declared in your subclass before you can call super.init()

So you have two ways of solving such issues:

  1. Change property type to optional (either SpriteComponent? or SpriteComponent!).
  2. Initialize every property either when you declare it or in your initializer before calling super.init

In your case first option suits better.

You can find more info about Swift two-phase initialization here:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html

This tutorial may also be helpful: (Adding Properties to Subclasses paragraph):
https://www.raywenderlich.com/121603/swift-tutorial-initialization-part-2

Did not understand process of initialize in swift programming

In answer to 1 -

From the Swift Programming Language -

“As mentioned above, the memory for an object is only considered fully
initialized once the initial state of all of its stored properties is
known. In order for this rule to be satisfied, a designated
initializer must make sure that all its own properties are initialized
before it hands off up the chain.”

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itun.es/au/jEUH0.l

So, until the object is fully initialised, the object is in an undefined state which may be "unsafe", so Swift requires all properties are initialised in phase 1.

In answer to 2

An initialiser function is a special case - its job is to set the object to its initial state, so you can modify 'constant' properties as the object is still in the process of being created -

“You can modify the value of a constant property at any point during
initialization, as long as it is set to a definite value by the time
initialization finishes.”

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itun.es/au/jEUH0.l

In answer to 3, because you are overriding a method with the same signature as the super class (the no argument init function). The override keyword indicates to the compiler that you know what you are doing. If the compiler silently let you re-declare a super class method you may not realise that you are doing it and get unexpected results.

In answer to the question regarding the consumption of memory, ARC will quickly reclaim the memory that was allocated for the first instance of the object. If this is a performance issue then it is fairly simple to refactor the AdminManagmentSystem class so that there is a function to reset the key on an existing instance -

class Admin : Person {

// Constant variable
let adminmanagmennt : AdminManagmentSystem

override init()
{
self.adminmanagmennt = AdminManagmentSystem(key: ""); // Line1 : Consume lots of memory
super.init(); // Line2 : its compalsurry to call super.init
var adminKey = super.calculatekey(); // Line3 : We can use any member or method of supper after callign init().
self.adminmanagmennt.key=adminKey; // You can use a property observer function if a simple assignment isn't enough
}
}

Error in Swift class: Property not initialized at super.init call

Quote from The Swift Programming Language, which answers your question:

“Swift’s compiler performs four helpful safety-checks to make sure
that two-phase initialization is completed without error:”

Safety check 1 “A designated initializer must ensure that all of the
“properties introduced by its class are initialized before it
delegates up to a superclass initializer.”

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11

Force user to use custom init method for the initialization

You can make it private , so user must need to init Test class with withSomeParameters

class Test:UIView {
private override init(frame: CGRect) {
super.init(frame: frame)
}

convenience public init(withSomeParameters myParam:Type) {
self.init(frame: CGRect.zero)
//Doing something nice!
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}


Related Topics



Leave a reply



Submit