What is the purpose of the initializer pattern other then in order to assure that the object is properly initialized by its superclass before the init method performs its initialisation.
Why is this necessary?
and
when we have a class which has more than one initialization method, why others shoud call the dedicated initialiser instead of superclass initialiser?
I'm coming from java background so don't fully understand this - the closest i could match in java was singleton pattern but the part others calling dedicated initialiser didn't make sense to me as in java you have a choice rather then you "should".
can any one elaborate....thx
The initializer pattern is necessary, because the super class whose initializer you are calling, can return any kind of object, not necessarily the instance of that class. That's how, for example, NSString works, it's actually a cluster of classes implementing different kinds of strings optimized for different usage patterns. So calling self = [super init] for NSString descendant makes self, for example, an NSCFString instance.
There's a pattern called Designated Initializer in Objective C. If the class has many initializer, one of them is chosen as designated, and all the other should be implemented by calling it, not the super. This is important for correctly overriding initializers in child classes, you should initialize only the designated one, and it will be called under all circumstances (assuming your code is well-written and takes advantage of designated initializers, of course :)
Related
I am new to Objective C. I have trouble with understanding the init() method. I have read these two lines on Apple website:
The init() method defined in the NSObject class does no initialization; it simply returns self. (https://developer.apple.com/reference/objectivec/nsobject/1418641-init)
You must use an init... method to complete the initialization process. (https://developer.apple.com/reference/objectivec/nsobject/1571958-alloc)
Do I need to call init() to initialize objects if "it does no initialization"? Why?
When an instance object is created with +alloc, it gets a fully set-up infrastructure and all ivars are set to 0, NULL, nil, 0.0 (or whatever ist the zero value for the ivar's type).
If this is enough for the class, there is no need to overwrite -init and it can simply use NSObjects init. (-init of NSObject simply does nothing.) This is the implementor's side. This is what you refer to at 1).
The user of the class (that code, that created the instance), has to send init to the newly created instance to give it the opportunity to initialize itself. This is what you refer to at 2).
As a user of the class, you simply cannot know and should not know, whether the class requires some code in its initialization process. So send the message, even if it might be useless.
From Apple Developer on Object Initialization :
If an object does not implement an initializer, Cocoa invokes the
initializer of the nearest ancestor instead.
Yes, you need to call some form of init to create your object on the heap. The init returns a point to the memory location. No, you don't need to write an init for your custom object unless the default set-everything-to-zero initialization is insufficient.
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.
I've read that you're not supposed to send messages to 'self' during an init. Unfortunately, you can't directly access the ivars belonging to your superclass (as far as I can tell). This leads to the situation where you need to access / set up the superclasses ivar in some way, but have no way to do so other than messaging self. (For reference, I'm writing custom UIControls to encapsulate repeated concepts in my application; while a lot of the logic is shared, and thus belongs in a superclass, the exact layout of each control needs to vary).
For example, a custom control needs to have a button. That button is arranged different compared to each other object in the view depending on the subclass in question, so I need to reference it for layout. As far as I'm aware, unlike ViewControlllers, UIViews don't have any callbacks to let you know about lifecycle events like 'willAppear' or 'didLoad'; init is the only place to place the code -- and the tutorials I've read on creating custom UIControls put it there, as well.
Am I misunderstanding something, or do I have no choice but to violate the rule about messaging self in my scenario? (Or create an extra method that has to be called after init... creating a new convention that's basically saying 'first you init, then you REALLY init'!)
Unfortunately, you can't directly access the ivars belonging to your superclass (as far as I can tell)
That is only in situations when the base class declares ivars #private. If it does not, you can access ivars using the -> operator on self, like this:
self->myBaseIntVar = 123;
By default, ivars have #protected access, so you should be able to access them unless the designers of your superclass have specifically withdrew this possibility by specifying private access.
Am I misunderstanding something, or do I have no choice but to violate the rule about messaging self in my scenario?
Another choice is passing values to the designated initializer of your base class:
-(id)init {
if (self = [super initWithSomeProperty:123]) {
}
return self;
}
I'm finally imposing some TDD on a project I'm working on, and running into the edges... I know the code I want but not how to test for it :)
The implementation I'm looking for is:
- (void) doSomething
{
FooBuilder *foo = [[FooBuilder alloc] init];
[foo doSomethingElseWithCompletionBlock:^{
[self somethingDone];
}];
}
So I want my test to verify that a) the method under test allocates a new FooBuilder and b) that method then calls a method on the new object.
How do I go about this? I started down the path of trying to mock the alloc class method but quickly determined that down that path lies madness.
Note I'm not testing FooBuilder itself with this test, just that the collaboration is there.
Normally, dependency injection is used to provide a fully-formed object, saying "instead of asking for this object, here you go, use this." But in this case, we want the ability to instantiate a new object. So instead of injecting an object, all we have to do is inject the class. "Instead of creating a specific class, here you go, instantiate one of these."
There are two main forms of dependency injection: "constructor injection" (I'll stick with the term "constructor" even though Objective-C separates this into allocation and initialization) and "property injection".
For constructor injection, specify the class in the initializer:
- (instancetype)initWithFooBuilderClass:(Class)fooBuilderClass;
For property injection, specify the class in a property:
#property (nonatomic, strong) Class fooBuilderClass;
Constructor injection is clearer, because it makes the dependency obvious. But you may prefer property injection. Sometimes I start one way and refactor toward the other, changing my mind.
Either way, you can have a default initializer that either calls -initWithFooBuilderClass: , or sets the property, to [FooBuilderClass class].
Then doSomething would start like this:
- (void)doSomething
{
id foo = [[self.fooBuilderClass alloc] init];
...
I ended up addressing this by adding a new class method to FooBuilder which takes a completion block as an argument. So I've effectively moved the instantiation and method call out of my object-under-test into the collaborator object. Now I can mock that single class method call.
I think this ends up being slightly better design than what I started with; the detail that there needs to be a new FooBuilder instantiated is hidden from users of the class now. It's also pretty simple.
It does have the property that it maintains the strong coupling between my object-under-test and the FooBuilder class. Maybe that'll bite me down the road - but I'm making the YAGNI bet that it won't.
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.