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:
- Change property type to optional (either
SpriteComponent?
orSpriteComponent!
). - 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
Swift Build Time Too Long When the Configuration Is 'Release'
How to Get the Scnvector3 Position of the Camera in Relation to It's Direction Arkit Swift
How to Pass a Class and Method to Create an Instance of a Class
Draw a Straight Line in Swift 3 and Core Graphics
Realmswift Initialize List:Cannot Specialize a Non-Generic Definition
Write into Settings Bundle in Swift
Computed (Nsobject) Properties in Swiftui Don't Update The View
Why Is Icloud Account/Ckcontainer Not Being Found
Trying to Add a Protocol to a Class Signature in Swift
Swift: No Idea How to Get Back the Selected Value from a Popover to the Calling Controller
Dynamically Call a Function in Swift
Send Mail with File Attachment
Passing Property Type as Parameter
How to Implement a Generic Struct That Manages Key-Value Pairs for Userdefaults in Swift
Xcode 8 Swift 3 Pitch-Altering Sounds
Swift Generics Protocols: Can Only Be Used as a Generic Constraint Problem
Skshapenode Is Not Responding to Physicsbody
Distributednotificationcenter - How to Pass Data Between Applications