Recommended instance variables initialization place for Cocoa Touch classes - objective-c

I'm feeling very stupid, but...what is the right way to init instance variables in custom types, derived from Cocoa Touch UI classes?
Say I have type, derived from UIViewController, let it be TRUIController.
I defined an ivar as follows:
#implementation TRUIController
{
NSNumberFormatter *_numberFormatter;
}
#end
And where should I put _numberFormatter initialization code, if I want it to be executed before any UI methods like viewDidLoad, etc?
In other languages I would create constructor, call base constructor and then init my ivars.
But that simply does not work in objective-c and Cocoa Touch.
In case described above,
If I write
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibBundleOrNil bundle:nibBundleOrNil];
if(self)
{
//init ivars
}
return self;
}
It won't work, I'll try other initWithBlaBla methods, and finally find init, which is actually called, in that case - initWithCoder:
Now, let's say I have class, derived from UITableViewCell. Again, need to init NSNumberFormatter ivar. Why can't I just override init:, call super and init my ivars?
What's the idea behind this strange design decision not to have single common initialization method for all types?
Is it the only way to initialize ivars in derived types? Every time do some research to figure out what method to override this time?
Have I missed something? Because it feels extremely stupid/unintuitive/error-prone

You have to do so overriding the designated initializer.
From the official documentation
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. As examples of designated initializers
there is NSView’s initWithFrame: and NSResponder’s init method. Where
init methods are not meant to be overridden, as is the case with
NSString and other abstract classes fronting class clusters, the
subclass is expected to implement its own.
Designated initializers should be clearly identified because this
information is important to those who want to subclass your class. A
subclass can just override the designated initializer and all other
initializers will work as designed.
When you implement a class of a framework, you often have to implement
its archiving methods as well: initWithCoder: and encodeWithCoder:. Be
careful not to do things in the initialization code path that doesn’t
happen when the object is unarchived. A good way to achieve this is to
call a common routine from your designated initializers and
initWithCoder: (which is a designated initializer itself) if your
class implements archiving.
Read the documentation for finding out which initializer is the designated one and override it.
According to the documentation of UIViewController initWithNibName:bundle: is the designated initializer for this class is so you should override that one, but if you are not programmatically instantiating your class (e.g. you're loading it from nib/storyboard) you have to override the archiving method initWithCoder:.
As suggested by the documentation you can create a routine for initialization and call it from both the designated initializer and the archiving method.

It generally makes sense to use the designated initializer as a starting point, but if you are not sure this is always the one that will be used that won't make all that much sense.
Personally I therefore prefer to create a setup method which is called from any init-method I know is likely to be used at some stage. For ViewControllers I normally call the setup method from viewDidLoad instead (unless of course there's any state that's needed before this stage).

Related

Is not calling [super init] in the init method ever correct?

In Microsoft's WinObjC UIApplication.mm file (at https://github.com/Microsoft/WinObjC/blob/master/Frameworks/UIKit/UIApplication.mm) the init method is implemented for both UIApplication and WOCDisplayMode.
Neither class' init method calls [super init], or any method from that family of methods that would eventually result in a call to [super init]. I've never seen this before, apart from the initialization of NSProxy objects.
I've reproduced the implementation as of this writing of WOCDisplayMode below for reference.
-(instancetype) init
{
_fixedWidth = 320.0f;
_fixedHeight = 480.0f;
_fixedAspectRatio = 0.0f;
_magnification = 1.0f;
_autoMagnification = TRUE;
_sizeUIWindowToFit = TRUE;
_operationMode = WOCOperationModePhone;
return self;
}
It seems to me that this could create a number of problems; for example, if one of the superclasses of UIApplication, like UIResponder, at some point overrode init itself, and set up internal state that future method calls depended on.
Why might the implementor have elected not to call [super init]? Is this ever a justifiable decision? Is it ever the correct one?
This definitely seems like an error on behalf of the author(s) of those classes.
NSProxy does not call [super init] because it is an abstract superclass and does not inherit from NSObject.
Since their implementation of UIApplication inherits from UIResponder, and WOCDisplayMode inherits from NSObject they should be calling [super init] in these classes.
According to the documentation on Object Initialization:
The requirement to invoke the superclass’s initializer as the first
action is important. Recall that an object encapsulates not only the
instance variables defined by its class but the instance variables
defined by all of its ancestor classes. By invoking the initializer of
super first, you help to ensure that the instance variables defined by
classes up the inheritance chain are initialized first. The immediate
superclass, in its initializer, invokes the initializer of its
superclass, which invokes the main init... method of its superclass,
and so on (see Figure 6-1). The proper order of initialization is
critical because the later initializations of subclasses may depend on
superclass-defined instance variables being initialized to reasonable
values.
I would recommend logging it as an issue on the project.

Can subclass override non-public methods

I have two classes: BatchDownloader, SpeechDownlader
BatchDownloader is the base class, and SpeechDownloader inherited it.
In BatchDownloader, whenever one file was downloaded, -(void)downloadComplete:task will be called.
But in SpeechDownloader, I also want to post a notification in downloadComplete:task.
Can I just write the method with the same name in SpeechDownloader's implementation ? or there is a better way ?
Thanks.
p.s. I don't want to make -(void)downloadComplete:task public, because it should only be called by itself.
If you implement a method in a subclass that has the same name as a private method in a superclass, your subclass method will be called on instances of your subclass.
i.e., if you implement a method in your superclass like this, without declaring it anywhere:
#implementation classA
- (void)doSomething {
NSLog("a");
}
Then, in your subclass implementation, implement a method with the same name:
#implementation subclassOfA
- (void)doSomething {
NSLog("b");
}
When you call doSomething on an instance of your subclass, the subclass implementation will be called instead of the superclass implementation, so the code in this example will result in "b" being printed to the console.
However, if you also want to access the superclass implementation of the method, you can use:
- (void)doSomething {
[super doSomething];
NSLog("b");
}
This will also call the superclass implementation. If you get a compile error (due to the method being private and super not appearing to implement it), you can use [super performSelector:#selector(doSomething)] instead to do exactly the same thing.
This happens because of the way the Objective-C runtime looks up method calls. Since these methods have exactly the same method signature (same name, return type and arguments [none]), they are considered equal, and the runtime always checks the class of the object before looking in superclasses, so it will find the subclass method implementation first.
Also, this means you can do this:
classA *test = [subclassOfA new];
[test doSomething];
And, surprise surprise, the console will print "b" (Or "a b" if you called the super implementation too).
If you implement the method with the same method signature it will be called faith your implementation, public or not.

Prevent ObjC "abstract" class' init method from being called while allowing [super init]?

Say I have a pseudo-abstract base class that users should not instantiate. Basically I want to throw a warning when they're trying to call init on the class, or return one of the concrete instances with default values.
However, the concrete implementations of that base class have to call [super init] in their initializers. That should of course be allowed.
How would I best go about this?
I was thinking that this should be fine:
#implementation KTPhysicsShape
-(id) init
{
// throw exception here or return concrete instance with default values
}
// this is what subclasses would call in place of [super init]:
-(id) internal_initFromSubclass
{
return [super init];
}
#end
Any concerns about this approach? I know others could still call the internal method, but I'm mostly concerned about disallowing init since that's what users would try to call foremost.
I have also worked at the problem of how to have effectively abstract classes, but I'm not that into this solution. It seems to me that it's going to make your subclass code look weird and harder to read for casual observers.
If you require that your subclasses do particular initialization in -init, yours may the only solution. But if you just want to ensure that they have subclassed, you can do that within -init:
-(id) init
{
NSAssert(![self isMemberOfClass:[KTPhysicsShape class]],
#"KTPhysicsShape must be subclassed!");
return [super init];
}
This indicates that your architecture has a serious flaw. The whole point of the designated initializer chain is that it can be executed in a predictable order without variation. Adding contractual obligations to the subclasses to not follow the normal chain adds fragility and unneeded complexity.
The crux of the flaw is that you have an abstract class that doesn't appear to be truly abstract; it can have concrete instances and that requires concrete initialization.
First, why can't you break the class into a truly abstract class and a concrete class?
If you can't (or don't want to -- certainly, more classes has costs of its own), then one solution is to break out the commonly used initialization operations into a separate method:
- (void) commonKTPhysicsShapeInit
{
....
}
That does not call super. This would not be declared in your header; it is an internal-to-implementation-only method, thus the name.
Then, let your subclasses call through the standard designated initializer that calls commonInit. For concrete instances of that class, have a separate initializer that both calls commonInit and does the concrete initialization dance.
It is similar to what you proposed, but presents the interface in a fashion that follows existing patterns more closely.

UITableViewController init vs. initWithStyle

the class ref says:
If you use the standard init method to initialize a UITableViewController object, a table view in the plain style is created.
i do not understand, where this behaviour comes from - i would like to see i in some code
or api but
UITableViewController has no init in its api
how could some base class' init know about a suitable default style for a derived class?
thanks for every hint
Every object has an init method, but a lot of classes have a so-called designated initializer. That is the main initializer, and the others are merely convenience methods calling that designated initializer.
According to that doc, in this case the init method probably looks something like this:
- (id)init
{
return [self initWithStyle:UITableViewStylePlain];
}
Methods from a superclass do not appear in the documentation of the derived class, except if the derived class overrides it and has something important to say about it. That's why you don't see init documented in UITableViewController, it's part of NSObject from which UITableViewController derives (through UIScrollView -> UIView -> UIResponder -> NSObject).
As for the second part of your question: a base class can (should) never know anything about derived classes. A derived class that wants a different default style simple overrides init again.
in UITableViewController.m
- (id) init
{
return [self initWithStyle:UITableViewStylePlain];
}
The init method will call the designated initializer.

Creating a class with no init method (Objective-c)

Is it possible to create a class with no init method so as to force all callers to create the object with a factory method instead?
So basically, you want to make sure that your class is never initialized using -init, right? You can't do exactly what you want to do, but you can come close.
Since you inherit from NSObject, you have an init method and there's nothing you can do to prevent it from being called. That said, you could override init to this:
- (id)init
{
[self dealloc];
#throw [NSException exceptionWithName:#"MyExceptionName" reason:#"Reason" userInfo:nil];
return nil;
}
This way, anytime someone calls your -init method, it kills the object, so practically speaking, your init method is pretty much un-callable.
If you really wanted to cause trouble for users of your class who use init, you can do:
#implementation MyClass
- (id) init
{
// Still have to make sure the runtime has initialised everything for "self"
self = [super init];
if (!self) return nil;
[self release]; // some say you should use [super dealloc]
[super doesNotRecognizeSelector:_cmd];
return nil;
}
#end
You invoke super's doesNotRecognizeSelector: because you might want to implement your own behaviour for unrecognised selectors for your class.
Depends. If you have your class inherit from NSObject, it will have the inherited init method (which does nothing to your instance variables). So in that sense, even if you really really wanted to not have an init method, you'd most likely still have one. So if your question was "Do I need to implement a trivial init method?", the answer is "no, you don't need to". However, if your question was "Do I need to call the init method if I didn't override it?", then the answer is "yes, you do". Whatever you do with NSObject subclasses, at some point you still need to call init after the object is created. Such is the way of life.
That being said, you most likely want an init method, unless your object initialization requires nothing more than zeroing your whole object.
Otherwise, if you choose to not inherit from NSObject or any of its subclasses and just inherit from nothing, which is clearly a bad idea because of how the NSObject class deals with everything the ObjC runtime needs to do and the requirements are quite high, then you'll potentially end up with no init method at all. But seriously, don't try this at home.
Sure. In Objective-C, there are no actual constructors. init-type methods are typically used to initialize a class, in the same vein as a constructor, but they're just a "normal" method (there's nothing special about them like there are with, e.g., Java constructors).
That said, unless your class does no initialization for its instances, you probably want to have some sort of init method.
NSObject implements an init method for you that does whatever it does. If your class has nothing to setup when it's instantiated then simply do not override the -(id)init method provided by NSObject. But you still call it when you create the instance.