[self release], [self dealloc] or [super dealloc] in init methods? - objective-c

I've just been reading up on how to properly fail in an init method and the docs seem to disagree with each other. One recommends throwing an exception while the others recommend cleaning up and returning nil. What's the current best practice here?

I believe that the generally accepted practice is to return nil on failure. But you do want to release self to avoid a leak:
-(id)init
{
if (self = [super init]) {
...
if (thingsWentWrong) {
[self release];
return nil;
}
...
}
return self;
}

The correct solutions (exceptions and/or [self release]; return nil;) having been covered, I'll address the incorrect solutions.
Don't send dealloc directly. That's release's job. (And if your code is ever running under GC, dealloc is inapplicable, and I could only speculate on what problems calling it would cause.)
Double-don't use super to send it directly. That would skip over your own dealloc implementation.

Cocoa's philosophy on exceptions is that they should only be thrown in situations that are programmer errors, like passing an illegal argument to a method. If something else goes wrong, the method should just return NO or nil, and hopefully report the details via an NSError** "out" parameter.
This includes -init methods. If the error situation is something that could legitimately occur in the finished product, then the method should release self (to avoid a leak) and return nil.

The method I've always used is cleaning up and returning nil. The three methods you mention in your question title may cause segfaults higher up in the call hierarchy, whereas returning nil will not. I believe that the Apple docs themselves say to return nil on failure. Where are you finding discrepancies?

Related

Is testing for self still necessary and/or meaningful? [duplicate]

This question already has answers here:
In Objective-C why should I check if self = [super init] is not nil?
(9 answers)
Closed 9 years ago.
A usual initialization sequence in an Objective-C instance (e.g. in the designated initializer) goes like:
- (id)initWithFrame: (NSRect)frame {
self = [super initWithFrame: frame];
if (self != nil) {
// Do your stuff.
}
return self;
}
This is a well known pattern, but is it really necessary to test if self is assigned? I mean, if something fails in the super method, wouldn't it rather raise an exception than just returning nil? Is it a safe pattern at all? What if the call to super had a problem but still returns a (random) pointer?
It's certainly a matter of defensive programming but it really looks exaggerating to have so many many tests for cases you know for sure that there's never a nil result. It makes of course a lot of sense to check self if you know that it can occur (which must be documented then).
Raising an exception is not reasonable behavior in an objective-c program when something goes wrong. Throwing exception should only used for critical, unrecoverable, programmer-error situations.
The correct way to signal error from an init method is to return nil and optionally fill in a passed NSError-pointer with more information. Testing if your super initializer returns nil prevents you from doing useless initialization, and helps avoid possible crashes like:
#implementation {
int _foo; // instance variable
}
- (id)initWithFrame: (NSRect)frame {
self = [super initWithFrame: frame];
if (self != nil) {
_foo = 2;
}
return self;
}
This will crash if the super initializer returns nil, because _foo = 2 is short-hand for self->_foo = 2, which would dereference a nil pointer. (Only message sends return nil when self is nil; accessing an ivar directly doesn't make that guarantee.)
Some classes, even Apple's own NS classes can return nil from an initializer, e.g. NSArray's and NSDictionary's initWithContentsOfFile: and initWithContentsOfURL: methods. Should those throw an exception instead? NO! They're easily detectable and easily recoverable cases. Throwing an exception would be nothing but a crutch for lazy programmers who can't be bothered to put in proper error-checking and a bother for those of us who do.
The question boils down to: Are there any (many) known classes that do return nil from an initializer?
I think there are few. Of course there are known cases (where the constructor often takes an NSError by reference) that have to return nil to point out an error.
But most other initializers either return the self argument or another instance of the class. If that's not the case it should be clearly expressed in the documentation, as code usually relies on object creation not failing.
So I think it's totally safe to omit the test for nil when you checked the superclass's behavior.
On the other hand the pattern is so omnipresent that co-developers might be confused about the omission and might point it out as an oversight. So if you plan to switch to a style without the condition it should at least be somehow communicated to your fellow developers.

What is meant by [self release] in Objective-C? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is calling [self release] allowed to control object lifetime?
What will happen if I use this code snippet?
[self release]
self descrements its own retain count by one, just like release would do with any other object.
The only situation however that I have so far come across, where such a call was appropriate, was the case where an init… method would fail and be expected to return nil and deallocate the just allocated instance.
In 9 out of 10 situations you shouldn't use [self release], I'd estimate.
Something like this (which basically forbids the calling of - (id)init;, for cases where you want to force the use of a particular - (id)initWith… method.):
- (id)init {
[self release];
NSString *reason = [NSString stringWithFormat:#"%# is not a valid initializer for the class %#", NSStringFromSelector(_cmd), NSStringFromClass([self class])];
#throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:reason
userInfo:nil];
return nil;
}
or this (which basically enforces the proving of an object on initialization)
- (id)initWithFoo:(Foo *)foo {
if (!foo) {//foo is required to be non-nil!
[self release];
return nil;
}
//proceed with initialization
return self;
}
These however are not the only ever occasions where [self release] would be appropriate. But merely the ones I've come across so far. (as Oliver correctly pointed out)
Edit: Self-invalidating NSTimers would probably be another (quite common, yet somewhat special) situation.
You will release yourself, what means that the object declares itself that it does not have to still live. If no one else retains tha object, it dies and its memory is freed
You have little reasons to do that, except if you want to create object that are not controlled by anyone else and are self controlled.
I mean, for example, there is the case where you may want to create an self living object that makes some treatments, and suicide when it has finished without having to tell anyone else it has finished.
Let's imagine for example a class whose purpose is just to send a message to a server :
You instanciate the class, as soon as it is istanciated it send a message to a server, it waits for the server answer, and if the answer is ok, it suicide. That way, you don't have to manage any server answer from within another class controller whose purpose is not to manage such events.
It just decrements the receiver’s reference count.

Reusing NSObjects by Overriding release in Obj-C

I am implementing an object reuse scheme using a singleton class.
What I do basically is:
MyClass* obj = [[MyClassBank sharedBank] getReusableItem];
The bank is just an NSMutableSet tweaked for optimum reusability. When I was happily implementing this Singleton, I had in mind that I will just do the following when I am done with "obj":
[[MyClassBank sharedBank] doneWithItem:obj];
Currently, My code would work if I where to use it this way, but I later realized that I sometimes add "obj" to an "NSCollection", and sometimes I call:
[theCollection removeAllObjects];
At first I thought about making my own class that is composed of a collection, then I would iterate the objects within the collection and call:
[[MyClassBank sharedBank] doneWithItem:obj];
But, that's too much of a hassle, isn't?
A neat idea (I think) popped into my mind, which is to override: -(oneway void)release;, so, I immediately jumped to Apple's documentation, but got stuck with the following:
You would only implement this method to define your own reference-counting scheme. Such implementations should not invoke the inherited method; that is, they should not include a release message to super.
Ao, I was reluctant to do that idea .. basically:
-(oneway void)release{
if ([self retainCount] == 1) {
//This will increment retain count by adding self to the collection.
[[MyClassBank sharedBank] doneWithItem:self];
}
[super release];
}
Is it safe to do that?
PS: Sorry for the long post, I want the whole idea to be clear..
EDIT:
How about overriding alloc alltogther and adding [[MyClassBank sharedBank] getReusableItem]; there?
Suggested method:
You're playing with the reference counting system. 99.9999999999999999% of the time this is a bad idea. I would highly recommend going with a different mechanism. Perhaps these objects could implement their own reference count that's independent of the retainCount? Then you could use that referenceCount to actually control when an object is ready to be re-used or not.
Not suggested method:
If, for some weird reason, you can't do that, then you could do the following thing that is still a bad idea and that i don't recommend you actually use:
You can override dealloc:
- (void)dealloc {
[ivar release], ivar = nil;
[anotherIvar release], anotherIvar = nil;
somePrimitive = 0;
// do not call [super dealloc]
}
- (void)_reallyDealloc {
[self dealloc]; // clean up any ivars declared at this level
[super dealloc]; // then continue on up the chain
}
Basically, the dealloc method would be the point at which the object is ready for re-use. When you're totally done with the object and finally want it to go away, you can use the _reallyDealloc method to continue on up the chain, eventually resulting in the object getting freed.
PLEASE don't do this. With things like Automatic Reference Counting, this is going to introduce you into a world of hurt and really bizarre debugging scenarios. A lot of the tools and classes and stuff depend on the reference counting mechanism to be working without alteration, so screwing around with it is usually not a Good Idea™.
For ppl who find this approach interesting/useful, Here is a cleaner way than calling [super dealloc]; directly (which is definitely bad)
//BAD!
//-(void)dealloc{
// for some reason, the retainCount at this point == 1
// if (![[BankStep sharedBank] purgeFlag]) {
// [self resetObject];
// [[BankStep sharedBank] doneWithItem:self];
// } else {
// [children release];
// [super dealloc];
// }
//}
by calling [[Bank sharedBank] purgeBank]; , set the flag to true, then remove all objects from the NSSet.
Adapted solution:
#Joe Osborn idea of using categories to implement a returnToBank Method!

Calling super in the implementation of an Objective-C block

Is calling a method on super supported in the implementation of an Objective-C block?
When I was calling a method on super an EXC_BAD_ACCESS error would be thrown but as soon as I changed those calls from [super methodToCall] to [self methodToCall] and let the message move up the responder chain it worked fine.
There is no implementation of -methodToCall in the instance of the class that the block exists in, but there is one in the superclass (that is, the class that self inherits from).
I'm just curious to learn the details as to why calling a method on super inside the implementation of a block was a problem in the first place (technically) so I can avoid it in the future. I have a suspicion it is related to how the variables are captured in the block and something about the stack and the heap, but I really have no concrete idea.
Note: the block implementation code is called up to a few seconds after the block is stored in a property, the property uses copy so I don't think it's a problem with the block's lifecycle, that all looks to be fine. Also, this was only crashing on the iPhone device (3G) but was working without crashing in the iPhone Simulator.
Results in EXC_BAD_ACCESS:
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[super didRetrieveItems];
} else {
[super errorRetrievingItems];
}
}];
Works perfect, implementations of -didRetrieveItems and -errorRetrievingItems are in the super-class.
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[self didRetrieveItems];
} else {
[self errorRetrievingItems];
}
}];
Technically, this is an issue with the Objective-C runtime, and the underlying mechanics of how calls to super actually work. Basically, they capture both the object which is the recipient of the message (self in all cases) and the class which implements the specific version of the method (the superclass of the class in which the method implementation occurs). Because a lot of the preparation for such a message send happens at compile-time, not runtime, I wouldn't be surprised if it interacted badly with blocks.
I would check to see if self is still valid when the message is about to be sent. Normally, any objects referenced in a block are automatically retained. Since super works a bit differently, it might mean that self is not getting retained like one would expect. One easy way to check this would be to use the calls to super as originally written, and simply leak the object referred to as self, and see if it works. If this turns out to be the problem, you might have to insert a dummy reference to self within the block to get that automatic memory management.
In the strictest sense, however, I'm not sure you can depend on this working forever and always. Although blocks can capture the current runtime state, it doesn't really make sense (from an OOP perspective) for them to break encapsulation and invoke superclass implementations, since the hierarchical level at which methods are implemented should be opaque to any external calling code. I would try to find another solution which doesn't depend on the inheritance hierarchy.
Results in EXC_BAD_ACCESS:
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[super didRetrieveItems];
} else {
[super errorRetrievingItems];
}
}];
Probably due to a bug in the compiler; try adding [self class]; or any other method call to self in that block and it'll probably work.
Works perfect, implementations of -didRetrieveItems and -errorRetrievingItems are in the super-class.
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[self didRetrieveItems];
} else {
[self errorRetrievingItems];
}
}];
I think you may be confused about one of the fundamental aspects of object oriented programming. You say that there are no implementations of those methods in your class, they exist only in the superclass.
Because of inheritance, your class effectively responds to said method calls, too. Just call 'em as you do above using self. It will work find and is exactly how you should be doing it!

Assigning to self in Objective-C

I'm from the C++ world so the notion of assigning this makes me shudder:
this = new Object; // Gah!
But in Objective-C there is a similar keyword, self, for which this is perfectly acceptable:
self = [super init]; // wait, what?
A lot of sample Objective-C code uses the above line in init routines. My questions:
1) Why does assignment to self make sense (answers like "because the language allows it" don't count)
2) What happens if I don't assign self in my init routine? Am I putting my instance in some kind of jeopardy?
3) When the following if statement fails, what does it mean and what should I do to recover from it:
- (id) init
{
self = [super init];
if (self)
{
self.my_foo = 42;
}
return self;
}
This is a topic that is frequently challenged by newcomers:
Wil Shipley: self = [stupid init];
Matt Gallagher: What does it mean when you assign [super init] to self?
Apple documentation: Implementing Initializers
Cocoa-Dev: self = [super init] debate
Basically, it stems from the idea that a superclass may have over-ridden the designated initializer to return a different object than the one returned from +alloc. If you didn't assign the return value of super's initializer into self, then you could potentially be dealing with a partially initialized object (because the object that super initialized isn't the same object that you're initializing).
On the whole, it's pretty rare for super to return something different, but it does happen in a couple of cases.
In Objective-C, initializers have the option of returning nil on failure or returning a completely different object than the one the initializer was called on (NSArray always does this, for example). If you don't capture the return value of init, the method might be executing in the context of a deallocated object.
Some people disagree about whether you should do the whole assign-to-self rigamarole if you don't expect to get something else back from the superclass initializer, but it's generally considered to be good defensive coding.
And yes, it looks weird.
It is true that init may return nil, if the initialization fails. But this is not the primary reason why you should assign to self when you implement your own initializers.
It has been mentioned before, but it is needed to stress even harder: the instance returned from an initializer may not be the same instance as the one you sent in, in fact it may not even be of the same class!
Some classes use this as a standard, for example all initializer to NSString and NSArray will always return a new instance of a different class. Initializers to UIColor will frequently return a different instance of a specialized class.
And you yourself can happely implement something like this if you want:
-(id)initWithName:(NSString*)name;
{
if ([name isEqualToString:#"Elvis"]) {
[self release];
self = [[TheKing alloc] init];
} else if (self = [super init]){
self.name = name;
}
return self;
}
This allows you to break out the implementation of some special case into a separate class, without requiring the clients of your API to care or even know about it.
All the other points here are valid, but it's important for you to understand as well that self is an implicit parameter to every Objective-C method (objc_msgSend() passes it) and can be written to, just like any other method parameter. (Writing to explicit parameters is generally frowned upon, unless they are out parameters.)
Typically, this is only done in the -init method, for the reasons others have stated. It only has any effect because self is returned from the method and used in the assignment id obj = [[NSObject alloc] init]; It also affects the implicit resolution of ivars, because, for example, if myVar is an ivar of my class, then accessing it in a method causes it to be implicitly resolved to self->myVar.
I'm still new to Objective C, but this post helped me in understanding this.
To sum it up, most init calls return the same object that self is already initialized to. If there is an error, then init will return nil. Also, some objects such as singletons or unique objects (like NSNumber 0) will return a different object than the one initialized (the singleton or a global 0 object). In these situations you need to have self reference that object. I'm by no means an expert in what is going on behind the scenes here, but it makes sense on the surface, to me.
If [super init] returns nil that means that you have been deallocated and your self parameter is now an invalid pointer. By blindly following the self = [super init] convention you will save you from potentially nasty bugs.
Consider the following non-typical initializer:
- (id)initWithParam:(id)param {
if (!param) {
// Bad param. Abort
self = [super init]; // What if [super init] returns nil?
[self release];
return nil;
}
else
{
// initialize with param.
...
}
}
Now what happens if my superclass decides to abort and return nil? I have been de-allocated and my self parameter is now invalid and [self release] will crash. By re-assigning self, I avoid that crash.