The use of [[self alloc] init] when writing factory methods - objective-c

I'm having trouble understanding the use of [[self alloc] init] when writing factory methods. I understand that factory methods are convenience methods to create instances of a class, and that they do the alloc, init, and autorelease for you. I can see how this is formed, for example in the declaration of an NSArray property with the factory method arrayWithArray:, or array, etc. called on it to set it up.
I can obviously see how this is different to an outright (explicit) call to alloc and init.
My issue with this is that I don't understand factory methods at a deeper level. I came across an explanation online that said instead of calling alloc and init explicitly, a class factory method could be used to basically encapsulate something like this:
+(instancetype)createWithString:(NSString *)string
{
return [[self alloc] initWithString:string];
}
But how do instancetype and [self alloc] effectively allow for subclasses to make use of the class factory method?

instancetype is a keyword that says "the return type of this method is the type of the class that this method was called on" (or a subclass). So, if you call [Baseclass createWithString:], the return type is Baseclass *. However, let's say you create a subclass that does not override this method. If you call [Subclass createWithString:], the return type is Subclass * (not Baseclass *).
When a class receives a message, self points to the Class object. So when calling [Baseclass createWithString:], self will point to the Baseclass object. However, when calling [Subclass createWithString:], self will point to Subclass instead, so if Subclass defines its own alloc or initWithString: methods (that is, it overrides them) its versions will be called instead.

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.

How Class Method can access Instance Method ?

I am from Actionscript Background. In Actionscript Class Method can access only Class Methods and Class properties.
But In Objective C,
How Class method gameResultAll can access Instance Method initFromPlist
+(NSMutableArray *)gameResultAll://Class Method
-(id)initFromPlist:(id)plist;//Instance Method
NSMutableArray *gameResults = [GameResult gameResultAll]; // (returns GameResult array)
Why [self init] method is called instead of [super init] to create an instance from class method.
Thanks in advance.
#import "GameResult.h"
#implementation GameResult
#define GAME_RESULT_KEY #"gameresult_key"
#define SCORE_KEY #"score"
+(NSMutableArray *)gameResultAll
{
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
for (id plist in [[[[NSUserDefaults standardUserDefaults] dictionaryForKey:GAME_RESULT_KEY] mutableCopy] allValues])
{
GameResult *gameResult = [[GameResult alloc] initFromPlist:plist];
[resultArray addObject:gameResult];
}
return resultArray;
}
//Designated initialiser
-(id)initFromPlist:(id)plist
{
self = [self init];
if(self)
{
if([plist isKindOfClass:[NSDictionary class]])
{
NSDictionary *resultDictionary = (NSDictionary*)plist;
_score = (int)resultDictionary[SCORE_KEY];
}
}
return self;
}
You asked:
How Class method gameResultAll can access Instance Method initFromPlist
It can access that method because you used the alloc method, which creates an instance of GameResult. Now that you have an instance, you can use instance methods in conjunction with this instance.
By the way, this is a very common pattern, a "convenience" class method that allocates an instance of an object (with alloc) and initializes the object (with init or some permutation of that). Or, as in this case, it can create an array of these objects.
You then go on to ask:
Why [self init] method is called instead of [super init] to create an instance from class method.
I can understand the confusion, but there is an important, yet subtle distinction in the behavior of these two.
Imagine this scenario:
At some future date, you subclass GameResult, e.g. ArcadeGameResult;
You implemented an init method for ArcadeGameResult that initializes some properties unique to this subclass; and
You happen to initialize a ArcadeGameResult instance like so:
ArcadeGameResult *agr = [[ArcadeGameResult alloc] initFromPlist:plist];
Because the initFromPlist uses [self init], it means that the the initFromPlist method of GameResult will end up calling the init method of the object (which in this example, is actually a ArcadeGameResult object). But if initFromPlist in GameResult called [super init] instead, it would not have called ArcadeGameResult's init method and thus initFromPlist would be problematic if ever used in conjunction with a subclass.
Bottom line, unless the method you're calling is the exact same method signature, it's safer to call the self rendition rather than the super rendition. It's a little more flexible in case you ever decide to subclass in the future.
There is a corollary to the counsel. When calling class methods from an instance method, you should refer to [self class] rather than the class name. So, imagine your GameResult class had a class method:
+ (void)someClassMethod
{
// do something
}
If you had some GameResult instance method that was going to avail itself of this method, you might be tempted to write:
- (void)someInstanceMethod
{
// do some stuff
[GameResult someClassMethod];
}
But that's not a good idea. You would instead use the following:
- (void)someInstanceMethod
{
// do some stuff
[[self class] someClassMethod];
}
They look very similar, but the latter lets you implement a someClassMethod in a subclass, and this instance method will still work. If you use the former construct, the subclassed class method wouldn't be called by someInstanceMethod.
These are subtle issues, and probably not critical for your current code sample. But hopefully it illuminates the choice of [self init] versus [super init] in this situation.
In Actionscript Class Method can access only Class Methods and Class properties.
That's not different in Objective-C either (because nothing else would make sense), so:
How Class method GameResultAll can access Instance Method initFromPlist
Only through a valid instance.
Why [self init] method is called instead of [self super] to create an instance from class method.
Because the latter is a syntax error, perhaps? Read a basic Objective-C tutorial.

How can I use a constructor class method in a subclass? [duplicate]

Apart from the standard [[MyClass alloc] init] pattern, some objects are built from static methods like MyClass *obj = [MyClass classWithString:#"blabla"]
According to widespread memory management guides (including Apple's), you're only responsible for releasing the objects that you alloc.
Can anyone provide me with a template for such methods? How do you return the allocated object ([self alloc]; return self;, perhaps)? How do you make sure that it will be released?
They are class methods, not static methods1. This specific type, creating autoreleased objects, can be referred to as "factory methods" (formerly also "convenience constructors"), and they are discussed in the Concepts in ObjC Guide. They go something like this:
+ (instancetype)whatsisWithThingummy: (Thingummy *)theThingummy {
return [[self alloc] initWithThingummy:theThingummy];
}
Where Whatsis is your class, and Thingummy is another class which your class uses.
If you're not compiling with ARC, the convention is to autorelease the instance before returning it.
The instancetype keyword was introduced by Clang for these kinds of methods; combined with self (which is the class object itself2 in a class method) it allows correct subclass behavior: the method produces an instance of the class which received the message.3 instancetype allows the compiler to do more strict typechecking than id.
An illustration of this usage in subclasses from the framework: +[NSString stringWithFormat:] returns an NSString instance, whereas +[NSMutableString stringWithFormat:], returns an instance of the subclass NSMutableString, without NSMutableString being required to explicitly override the method.
As discussed by the [Fundamentals][1] doc, there are other uses for these factory methods, such as accessing a singleton, or appraisal of the necessary memory allocation before it's performed (possible, but less convenient, with a standard alloc/init pair).
1"Static methods" in Java or C++, "class methods" in Objective-C. There's no such thing as static methods in ObjC
2Whereas in an instance method self is, sensibly, a reference to the instance.
3Previously, like the usual initialization methods (initWith...), you would have used id as the return type. Using a specific class name unnecessarily forces subclasses to override the method.
The objects returned from factory methods should be autoreleased, meaning they'll be cleaned up when the associated autorelease pool is drained. This means that you don't own the returned objects unless you copy or retain them. Following is an example of a factory method:
+ (id)myClassWithString:(NSString *)string {
return [[[MyClass alloc] initWithString:string] autorelease];
}
These methods are simply returning an autoreleased version of the object.
+(MyClass*)class
{
MyClass* object = [[MyClass alloc] init];
return [object autorelease];
}
The modern way to do this with ARC and the latest complier is:
+ (instancetype) myClassWithString:(NSString *)string {
return [[MyClass alloc] initWithString:string];
}
No need to autorelease with ARC.
instancetype provides better compile time checks whilst making subclassing possible.

Class methods which create new instances

Apart from the standard [[MyClass alloc] init] pattern, some objects are built from static methods like MyClass *obj = [MyClass classWithString:#"blabla"]
According to widespread memory management guides (including Apple's), you're only responsible for releasing the objects that you alloc.
Can anyone provide me with a template for such methods? How do you return the allocated object ([self alloc]; return self;, perhaps)? How do you make sure that it will be released?
They are class methods, not static methods1. This specific type, creating autoreleased objects, can be referred to as "factory methods" (formerly also "convenience constructors"), and they are discussed in the Concepts in ObjC Guide. They go something like this:
+ (instancetype)whatsisWithThingummy: (Thingummy *)theThingummy {
return [[self alloc] initWithThingummy:theThingummy];
}
Where Whatsis is your class, and Thingummy is another class which your class uses.
If you're not compiling with ARC, the convention is to autorelease the instance before returning it.
The instancetype keyword was introduced by Clang for these kinds of methods; combined with self (which is the class object itself2 in a class method) it allows correct subclass behavior: the method produces an instance of the class which received the message.3 instancetype allows the compiler to do more strict typechecking than id.
An illustration of this usage in subclasses from the framework: +[NSString stringWithFormat:] returns an NSString instance, whereas +[NSMutableString stringWithFormat:], returns an instance of the subclass NSMutableString, without NSMutableString being required to explicitly override the method.
As discussed by the [Fundamentals][1] doc, there are other uses for these factory methods, such as accessing a singleton, or appraisal of the necessary memory allocation before it's performed (possible, but less convenient, with a standard alloc/init pair).
1"Static methods" in Java or C++, "class methods" in Objective-C. There's no such thing as static methods in ObjC
2Whereas in an instance method self is, sensibly, a reference to the instance.
3Previously, like the usual initialization methods (initWith...), you would have used id as the return type. Using a specific class name unnecessarily forces subclasses to override the method.
The objects returned from factory methods should be autoreleased, meaning they'll be cleaned up when the associated autorelease pool is drained. This means that you don't own the returned objects unless you copy or retain them. Following is an example of a factory method:
+ (id)myClassWithString:(NSString *)string {
return [[[MyClass alloc] initWithString:string] autorelease];
}
These methods are simply returning an autoreleased version of the object.
+(MyClass*)class
{
MyClass* object = [[MyClass alloc] init];
return [object autorelease];
}
The modern way to do this with ARC and the latest complier is:
+ (instancetype) myClassWithString:(NSString *)string {
return [[MyClass alloc] initWithString:string];
}
No need to autorelease with ARC.
instancetype provides better compile time checks whilst making subclassing possible.

Object Makeup, how its constructed?

These are fairly simplistic questions, but something that I wanted to get right in my head before continuing...
#interface BasicTire : NSObject {
}
#end
#interface SnowTire : BasicTire {
}
#end
When you call [SnowTire init] the included [super init] calls [BasicTire init] which in turn calls [NSObject init]? (i.e. a cascade running up to the parent/superclass.
When you [SnowTire alloc] you are creating a single new object, that includes the the functionality of its superClass. Am I right in thinking your not creating multiple objects that are linked in some fashion (i.e. SnowTire > BasicTire > NSObject).
Just wanted to check ...
gary
Yes, normally initializers call superclass initializers. This is done explicitly in the implementation of the init method. While it's possible to call other initializers of the same class or its superclass, it's necessary to make sure that the "designated initializer" always get's called.
If an object does not implement init (or the initializer in question), the one from the superclass is called (like with any other method). This is not seldom, since in Objectve-C instance variables are always initialized to zero (in alloc) and so it's often not necessary to implement a specialized init.
alloc just allocates memory and sets the "isa pointer" of an object which determines an objects class. What you get from it is one uninitialized object (not a linked list) which has room for all of its instance variables (including super classes).
Yes. Each initializer must call the designated initializer for the superclass, all the way up to NSObject. It is also important that each initializer assigns the the result from the super initializer to self. Since an initializer is not required to return the same instance that you send the initialize message to.
Yes. alloc initialized enough memory on the heap for the objects instance variables, and clears this memory with zeros. This way all pointers will be nil, booleans false, etc. And then it sets the isa pointer to the class of the new object.
When you call [SnowTire init] the included [super init] calls [BasicTire init] which in turn calls [NSObject init]? (i.e. a cascade running up to the parent/superclass.
You implement both -[SnowTire init] and -[BasicTire init], so you can just look at your implementations to see that:
Your -[SnowTire init] uses [super init] to call -[BasicTire init].
Your -[BasicTire init] uses [super init] to call -[NSObject init].
[super init] always calls the next available implementation, even if it's not in your immediate superclass. If you don't implement -[BasicTire init], then the [super init] expression in -[SnowTire init] will call -[NSObject init]. That's fine, because you apparently decided that a BasicTire doesn't need any initialization. (If it does, then your omission of -[BasicTire init] was a mistake.)
When you [SnowTire alloc] you are creating a single new object, that includes the the functionality of its superClass. Am I right in thinking your not creating multiple objects that are linked in some fashion (i.e. SnowTire > BasicTire > NSObject).
Yes. Every object has a class (in a variable named isa, as in “this instance is a SnowTire”), and every class has a superclass and a metaclass. -alloc and -init, like all Objective-C methods and C functions, each only return one thing—in this case, one instance with one class.
So, for example, when you send a gripTheSnow message to your snow tire, it uses SnowTire's implementation of that method. If you send a retain message, well, you didn't implement retain in SnowTire and you didn't implement it in BasicTire, so it uses NSObject's implementation. The runtime searches, starting from the object's class (in this example, SnowTire), in a straight line up the class hierarchy, ending at a root class such as NSObject.