In Aaron Hillegass' Objective-C programming book, he gives a few rules on writing custom init methods. One of the rules is that "if the designated initializer of your class is different from the designated initializer of its superclass, you must override the superclass' designated initializer so that it calls the new designated initializer (of your new class)"
Why is this mandated. The only issues I see is that any instance variables in your class will be initialized to null until you explicitly initialize them using their setter. What is the problem with that?
This is because every initializer for a class must go through the designated initializer for the class, that ensures all common setup occurs in one place. Even the superclass' designated initializer should go through your subclass' one, should you make it designated, otherwise setup occurring in your designated initializer could be missed by naïve clients calling into a different initializer.
because it make sure all init for object must call your class designated initializer. If not override designated initializer of its superclass what happen if current class (your custom class) init with one super's initial (designated or convenience) method? your designated initial never called
Related
The required modifier is "to indicate that every subclass of the class must implement that initializer" :
class SomeClass {
required init() {
// initializer implementation goes here
}
}
This entails that the subclasses don't have to inherit the superclasses' initializers. In fact, this Stackoverflow answer says that if a subclass has a designated initializer of its own, then it doesn't have to inherit the superclass' initializer.
However, the Swift documentation says that every class has to have a at least one designated initializer that "calls an appropriate superclass initializer to continue the initialization process up the superclass chain."
My questions are:
Can a subclass not inherit the superclass' initializer and, if so, in what cases it is beneficial to not inherit it?
What exactly does the required initializer do and in what case is satisfying the initializer inheritance requirement necessary?
Try and think about it in terms of what initialization does for an object. It sets values to parameters that do not have values set to them yet that need values set before use. See: https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID228. So each class needs to have a way to initialize it and if necessary deal with setting variables or passing that responsibility along the subclass chain. The required init() function should be used as a unique case where somewhere in the initialization chain a special property is computed/set in required init() of a super class that makes it a requirement to call required init() in a subclass/subclasses of it. You do not need to write override required in this case.
what is this saying as stated in apples doc:
Sometimes the designated initializer of a superclass may be sufficient for the subclass, and so there is no need for the subclass to implement its own designated initializer. Other times, a class’s designated initializer may be an overridden version of its superclass's designated initializer. This is frequently the case when the subclass needs to supplement the work performed by the superclass’s designated initializer, even though the subclass does not add any instance variables of its own (or the instance variables it does add don’t require explicit initialization).
Apple's Documentation
Is it saying that i don't have to create a designated initializer for the subclass and the superclass designated initializer will suffice and if so how will the subclasses properties be initialized? and in what scenario if this allowed? How would that work?
Also if your overriding the DI how can you call that method from the subclass as the parent class has the same DI as you do? What does it mean that it needs to supplement the work?
Example:
There is a superclass A with an initWithName: DI.
Now you create subclass B. If you want the same DI and you don't need any additional initialization, then there is nothing to do with the init method. You simply call:
B *someBObject = [[B alloc] initWithName:#"A Name"];
This creates the B object and calls the initWithName: method from A.
Now if your B class needs to do supplemental work in the initWithName: method, then you add this to B.m:
- (instancetype)initWithName:(NSString *)name {
self = [super initWithName:name];
if (self) {
// do some additional stuff to initialize this "B" instance
}
return self;
}
I read some material which says that the designated initializer is the "most complete" initializer in the initializer list.
But for example in UIView initWithFrame:(CGRect)Frame and initWithCoder:(NSCoder*)aDecode both take 1 parameter, how to decide which one's is the UIView's designated initializer?
When you have access to the source, you can recognize the designated initializer as the one that calls super init while all the others just call that one either directly or indirectly - assuming the author follows this convention. They might also use the NS_DESIGNATED_INITIALIZER macro to make this explicit (read more here). When you don't have access to the source code, as is the case with Apple's classes, then they need to tell you somehow - luckily they do so in the class references - e.g. you can see in the reference for UIView that initWithFrame: is the designated initializer.
Command + click the initializer you want to know about. In the documentation it will be mentioned if the initializer is the designated or default initializer.
For UIView default initializer is:
- (instancetype)initWithFrame:(CGRect)frame; // default initializer
I'm building an iOS app in Swift and drawing on the Lister sample project Apple provides.
Lister uses two model objects: List and ListItem. I found that both of them do not call super.init() in their initializers even though they subclass NSObject.
However, in the Objective-C version of Lister, both model objects (AAPLList and AAPLListItem) do call [super init].
The Swift Programming Language clearly states that “designated initializers must call a designated initializer from their immediate superclass.” (Rule 1 of Initializer Chaining in Initialization)
What's going on here? Why is this an exception and if you shouldn't always call super.init() in a subclass, what rules do apply?
Even though I can't find a place in the documentation where this is described, what happens is that the default superclass initialiser is called at the end of the subclass initialiser if that is the only initialiser of the superclass, and it wasn't called explicitly.
NSObject only has the default initialiser (init()); you can see that the superclass initialiser is called at the end of the subclass initialiser by attempting to reference self (eg. println(self)) in a constructor that does not call super.init(): You are not allowed to do it because the class is not fully initialised at that point.
If you want to use self somewhere in the constructor, the object needs to be fully constructed at that point, so you need to call super.init() manually before then.
Reading through Apple's documentation on Tips and Techniques for Framework Developers, I came across this statement about designated initializers:
A designated initializer is an init method of a class that invokes an
init method of the superclass. (Other initializers invoke the init
methods defined by the class.) Every public class should have one or
more designated initializers.
(Emphasis added.)
Based on my understanding—and indeed, the very use of the word "designated"—a class should have only one designated initializer. But according to the documentation, multiple designated initializers are acceptable.
Assuming that you have two (or more) designated initializers, their role is to call the superclass's designated initializer in order to guarantee proper object initialization. But if both designated initializers are calling the same superclass's designated initializer, then why was there the need for more than one in the first place? Shouldn't the class be refactored to funnel all the other init methods to the singular designated initializer?
I'm just a bit confused as to what use case or design pattern would call for multiple designated initializers?
You would do this when you want to have a different initialization for different objects of the same class. One example is class clusters, like NSNumber. It has quite a few initializers for the different types of numbers they can hold. To provide the most accurate representation, the class should hold its value in the same format it received it in, instead of casting. This means the initializers can't simply call a common initializer and return. They need to do some custom work. This makes them a designated initializer.
Another example would be a document class which needs to do some initialization only for new files and some other initialization only for documents being opened. Both of these initializers will call their super implementation, which in turn calls the plain init method to do common initialization. However, since they do more than simply calling another initializer with a default value, they are considered designated initializers.