Is there a bug in NSOperation in Mac OS X 10.6?
If I release an instance of NSOperation
before sending -init
to it I get a segmentation fault
.
Reasons I think this is valid code:
- Apple does this in its documentation.
- Gnustep does it in its
implementation of NSNumber
, so it's fairly certain that this is in Apple's code too. (At least was.) NSObject
s-init
doesn't do anything, therefore-release
, which belongs toNSObject
should be working before that.
// gcc -o test -L/System/Library/Frameworks -framework Foundation test.m
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
NSOperation *theOperation = [NSOperation alloc];
[theOperation releas开发者_JAVA百科e];
}
- What do you think, is this a bug?
- Can you show me an example of another class that has the same behavior?
- Any idea why this is happening?
Sending any message other than init
to an object that has not been initialized is not valid code AFAIK. Call the superclass initializer and then release and I'm betting it won't crash (although having one class's initializer return a completely unrelated class strikes me as doubleplusungood).
There is nothing remotely valid about that code.
Rewrite your -init as:
- (id) init
{
if (self = [super init]) {
[self release];
NSNumber *number = [[NSNumber alloc] initWithInteger:6];
return number;
}
return self;
}
Of course, the code is still nonsense, but it doesn't crash.
You must always call through to the super's initializer before messaging self. And you must always do it with the pattern shown above.
I thought you need to initialize your superclass before calling release, but according to this example in Apple's docs that's not the case.
So it may be a bug, but certainly not an important one.
My previou analysis was not really correct.
However, I want to point that this issue can happen with different classes. It actually depends on which class you're subclassing. Subclassing NSObject is no problem, but subclassing NSOperation, NSOperationQueue, and NSThread is an issue, for example.
And it happens because just like YOU might do, the classes you subclass might allocate stuff in their -init
method. And that's also where you set to nil
the variables you have not allocated yet (and might do so later in your code).
So, by calling -release
on yourself without a previous -init
, you might cause one of your parent classes to release object that it had not allocated. And they can't check if their object is nil
, because it didn't even have the opportunity to init every object/value it needs.
This also might be the reason why releasing NSOperation without init worked on 10.5 and doesn't work on 10.6. The 10.6 implementation have been rewritten to use blocks and Grand Central Dispatch, and thus, their init
and dealloc
methods might have changed greatly, creating a different behavior on that piece of code.
精彩评论