supplement
- 2020.7.14: No need to add convenience constructor in extension
convenience
The keyword
OC initializer
@implementation TestView - (instancetype)init { NSLog(@"111 before super init"); self = [super init]; NSLog(@"111 after super init"); return self; } - (instancetype)initWithFrame:(CGRect)frame { NSLog(@"111 before super initWithFrame"); self = [super initWithFrame:frame]; NSLog(@"111 after super initWithFrame"); return self; } @end @implementation TestView2 - (instancetype)init { NSLog(@"222 before super init"); self = [super init]; NSLog(@"222 after super init"); return self; } - (instancetype)initWithFrame:(CGRect)frame { NSLog(@"222 before super initWithFrame"); self = [super initWithFrame:frame]; NSLog(@"222 after super initWithFrame"); return self; TestView2 * TestView2 = [[TestView2 alloc] init];Copy the code
What was the final print?
222 before super init
111 before super init
222 before super initWithFrame
111 before super initWithFrame
111 after super initWithFrame
222 after super initWithFrame
111 after super init
222 after super init
Copy the code
Why is that?
That is, what is the flow that the OC constructor executes?
Execute the convenience initializer first, and call the parent class’s convenience initializer, and then execute from the specified initializer of the child class up.
If [super init] is not executed in a convenience initializer, the specified initializer cannot be called.
- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
Copy the code
Swift initializer
// Both omit required init? (coder: NSCoder) class A: UIView { convenience init() { print("111 before convenience") self.init(frame: CGRect.zero) print("111 after convenience") } override init(frame: CGRect) { print("111 before design") super.init(frame: CGRect.zero) print("111 before design") } } class B: A { convenience init() { print("222 before convenience") self.init(frame: CGRect.zero) print("222 after convenience") } override init(frame: Print ("222 before design") super.init(frame: frame) print("222 after design")}}Copy the code
The result is as follows
222 before convenience
222 before design
111 before design
111 before design
222 after design
222 after convenience
Copy the code
The swift result is actually more understandable.
Only swift can not write, otherwise it will report errors, must conform to the principle.
Initialization principles for class types (principles for initializer calls)
- The design initializer must call a design initializer from its immediate parent.
- The convenience initializer must call another initializer from the same class.
- The convenience initializer must eventually call a design initializer.
Two-phase initialization (principle of property initialization)
- The design initializer must guarantee that all attributes of all classes have values. As long as all attributes of the parent class have values, its memory is considered fully initialized and phase 2 is entered.
- The parent class’s initializer ends, and the subclass’s design initializer can perform additional customizations, after which the subclass’s convenience initializer can perform additional customizations.
inheritance
- If no design initializer is defined, all design initializers of the parent class are automatically inherited
- If a subclass overrides all the design initializers of its parent class, it automatically inherits all the convenient initializers of its parent class
In other words, if a subclass overrides only the design initializers that are not part of its parent class, or if it has its own initializer, it does not have a corresponding facilitation initializer.
The structure of the body
There are no convenience initializers for structs, only design initializers, and there is no inheritance, so there is no complexity. But there are caveats:
// If an initializer is specified, then a must be given the default value. struct T { var a: Int }Copy the code
Kotlin initializer
Due to recent Android related development. So I also put kotlin’s initializer here just as a reminder. Not following the single responsibility principle, shame.
The whole idea is almost identical to that of the Swift initializer, with similar mechanisms to secure initialization.
- If a subclass has a primary constructor, the base class must be initialized immediately in the primary constructor.
- A subclass that does not have a primary constructor must be used in each secondary constructor
super
The keyword initializes the base class, or another constructor in the proxy
// If you want subclasses to inherit, you must add the 'open' keyword open class A(context: context): View(context) {// This' init 'function is analogous to the body of the main constructor init {println("A main constructor executes ")} constructor(context: context, name: String): Open fun testOverride() {}} Open class B(context: context) : this(context) {// Open fun testOverride() {}} open class B(context: context) : A(context) {init {println("B primary constructor ")}} class C: B {// If there is A primary constructor, there is no way to use 'super(context)' constructor(context: Context): Super (context) {println("C second constructor execution ")} override fun testOverride() {super.testoverride ()}} = = = = = = = = = = = = = = = = = = = = = = the execution result = = = = = = = = = = = = = = = = = = = = = = = A main constructor B main constructor perform C second constructorCopy the code
Different from the Swift initializer
Swift can print some information before super.init(), but can’t really use the self keyword either because self is not initialized at this point.
Kotlin cannot print information before super.init().
thinking
If you add an init function to class C, when does the inside of that function print?
Reference Documents:
Swift Official Documents
Novice tutorial