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

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.

Related

Objective C object alloc and release

I am new to objective C. I want to know why some classes do not need alloc when building an object. For example, the class NSNumber. To build an object:
NSNumber * strangeNum;
strangeNum = [NSNumber numberWithInteger:100];
No alloc and no release are needed.
But if I define a class myself, say myClass and build an object. I need to
myClass * myObj=[[myClass alloc] init];
...
[myObj release] // if without ARC
Can somebody explain this in detail? Thanks a lot.
The release method has been pretty much obsoleted by ARC (automatic reference counting), and you'll rarely, if ever, come across it with newer (the past couple years) code. To understand why you don't call release on an object you get from numberWithInteger:, you need to read the memory management policy for Objective-C, which can currently be found at this link.
The alloc method is a class method, and is the canonical way to allocate memory for any class which descends from NSObject. Classes may have any number of class methods, and a class method can create an object on your behalf. Somewhere in the chain of method calls, alloc will be called, it is just that for Foundation classes, which you don't have the source for, you don't see it.
First case - +[NSNumber numberWithInteger:]. It's a class factory method. From Apple documentation:
Class factory methods should always start with the name of the class
(without the prefix) that they create, with the exception of
subclasses of classes with existing factory methods. In the case of
the NSArray class, for example, the factory methods start with array.
The NSMutableArray class doesn’t define any of its own class-specific
factory methods, so the factory methods for a mutable array still
begin with array.
Class factory method return autoreleased object. Usually it's used as a simple shortcut, that calls corresponding init method:
+ (NSNumber)numberWithInteger:(int)intVal {
return [[[self alloc] initWithInteger:intVal] autorelease];
}
Second case is an explicit creation of NSNumber instance. Because you didn't call autorelease right after instance creation, you should call release after you've finished using object to free allocated memory.
So, object instance in both cases built trough alloc and init calls sequence.
Actually NSNumber does need an alloc, but you are using a static method which does the alloc.
If you were to see the source code for NSNumber, its static method(non instance method) for numberWithInteger would probably be something like this
-(NSNumber)numberWithInteger:(int)intVal {
NSNumber num = [[NSNumber alloc] init];
*Some magic*
}
Basically Apple have just made some it easier for you.

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

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.

Objective C - is init a bad place to implement a factory?

I implemented the old init-as-a-factory pattern, but in one particular case (but not others!) I get a warning from the analyser regarding memory leaks. And indeed, looking at the Cocoa Memory Management Policy rules, it is alloc, not init, which can return +1-retain-count objects.
So it appears that:
Releasing self and returning a new object from init is, strictly speaking, against the rules.
Many places on the internet promote this technique, and because of the tandem nature of alloc/init this does work.
The analyser sometimes complains about this, and sometimes doesn't.
So... have we been doing this wrong all along?
you can implemented init like this, which should release self to balance the retain count from alloc call.
- (id)initWithSomething:(id)something
{
[self release]; // don't need this line for ARC
self = nil;
return [[PrivateSubClass alloc] initWithSomething:something];
}
and it if very often to implement init as a factory method. e.g. NSArray, NSDictionary, NSString
As gaige said, it will be much more clearer if you post a piece of code rather than explanations.
Anyway, you can move your factory to the class method, so you will have no such problem at all. I mean something like this:
MyClass* instance = [MyClass instanceWithParameters:params];
#interface MyClass
+ (MyClass*) instanceWithParameters:(ParamType)params;
#end
Without knowing what is the code that is causing the analyzer's behavior it's hard to tell, but as a general rule, here's a couple of compiler-friendly ways to define init/factory methods.
Classic alloc/init
- (instancetype)initWithParameter:(id)parameter {
if(self = [super init]) {
_parameter = parameter;
}
return self;
}
Usage
MyCustomClass * myInstance = [[MyCustomClass alloc] initWithParameter:foo];
This will produce an instance with a +1 retain count. Under ARC this will be automatically managed properly since it follows the NARC rule (New, Alloc, Retain, Copy).
For the same reason, in pre-ARC environments it has to be explicitly released by the client.
Custom factory method
ARC
+ (instancetype)canIHazInstanceWithParameter:(id)parameter {
return [[self alloc] initWithParameter:parameter]; // assuming -initWithParameter: defined
}
Pre-ARC
+ (instancetype)canIHazInstanceWithParameter:(id)parameter {
return [[[self alloc] initWithParameter:parameter] autorelease]; // assuming -initWithParameter: defined
}
Usage
MyCustomClass * myInstance = [MyCustomClass canIHazInstanceWithParameter:foo];
Both in ARC and pre-ARC the method returns an autoreleased instance (this is clearly more explicit in the pre-ARC implementation), which doesn't have to be managed by the client.
Remarks
You may have noticed the instancetype keyword. That's a handy language extension introduced by Clang, that turns the compiler into a dear friend when implementing your own constructors/factory methods. I wrote an article on the subject, which may be relevant to you.
Whether factory methods are preferable to init methods is debatable. From a client perspective it does not make much difference under ARC, provided that you carefully follow the naming conventions, even though I personally tend to expose factory methods in the interface, while implementing custom init methods only internally (as I did in the examples above). It's more a matter of style than an actual practical concern.

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.