Monday, December 8, 2008

From C++ to Objective-C

From C++ to Objective-C (PDF) looks like a concise and useful book for experienced programmers who want to learn about Objective-C (via John Haugeland). Unlike the various paper books I’ve seen, it isn’t full of step-by-step example projects. Unlike Apple’s book, it has lots of comparisons with C++ and advice about common techniques. However, it could use some technical review. For example, page 25 cites Wil Shipley’s incorrect recommendation to avoid self = [super init]. In fact, this idiom makes sense and is recommended by Apple.

8 Comments RSS · Twitter

Hello,

I was informed of your blog entry about my documentation by a reader. I am pleased to see that you liked it ! The reader gave me the link so that I can see more information about the self = [super init] debate.
It's true that my documentation could contain errors, since I wrote it at first time while learning Objective-C. Writing it as an exercise helped me understand Objective-C by forcing me to ask myself many questions. Eventually it was a useful resource for others.
I am currently upgrading it for Objective-C 2.0, so it's time for new corrections ! I will take this yours in account. My new opinion for [super init] is :
self = [super init] is theoretically not required, since "self" is no more than a (hidden) local variable. Assigning it as no incidence outside the method. What is important is how you are using it in your init method, and how you are not ignoring the result of [super init]. The assignation is just a way to prevent many errors when using "self" (explicitely with method calls or implicitely with ivars).
I think that understanding "Handling Initialization Failure" from Apple's documentation is a major point in the way of fully understanding self = [super init].

Do you agree ?

PS :
When I am done with translating the new version in english, can I send it to you for reviewing ?

Hi Pierre,

Sorry for not contacting you directly first. I was planning to do so after reading more of the book. That particular example just jumped out as I was skimming. I’d be happy to review your new version, although I cannot promise that I will be able to do so in a timely manner.

As to your specific question: technically you do not need to assign to self; you could instead assign to a local variable with a different name. What is important is that you save the return value of [super init], use it to access the ivars, and then return it. The value of self that’s passed as the (invisible) first parameter should be ignored.

Hi,

"As to your specific question: technically you do not need to assign to self; "
Ok, we agree ! You wrote it better than I did.
There are a few other parts of the doc which have been touched for the new version, especially the "mutator" part; don't be surprised if you see new mistakes, but do not hesitate to tell me.

>I’d be happy to review your new version, although I cannot promise that I will be able to do so in a timely manner.
No problem, this is a long-run free-time project with no deadline.

Regards,

Pierre

While I am there...
AFAIK, Apple's documentation does not handle properly that case :
-[super init] returns a "new" self that should be used
-for some reason, after that, the initialization should fail (we could not initialize a resource for instance)
-[self release] must be used and nil must be returned
-but what about the "old" allocated self ? It must have been saved to be released as well, shouldn't it ?

Pierre,

If the [super init] returns a "new" self, then it was [super init]'s responsibility to release the "old" self.

After [super init] returns a value, that is the one and only "self", you should not have any more dealings with the previous "self"

I agree with Clark. You only have to release if the failure happens in your code.

Hi,

Let's take a subclass of NSManagedObject and it's designated initializer :

-(id) initWithManagedObjectContext:(NSManagedObjectContext*)managedObjectContext
{
  NSEntityDescription* entity =
    [NSEntityDescription entityForName:[self className] inManagedObjectContext:managedObjectContext];
  NSLog(@"1: %p", self);
  if (!((self = [super initWithEntity:entity insertIntoManagedObjectContext:managedObjectContext])))
    return nil;
  NSLog(@"2: %p", self);
  return self;
}

-(void) dealloc
{
  NSLog(@"dealloc");
  [super dealloc];
}

The log shows that as expected, the value of self is changing. But dealloc is not called. So, how is the "old" self released ?

The short answer is that you aren’t supposed to worry about how the old self is released. In this case, my guess is that there’s a single immortal object that’s reused when creating different instances.

Leave a Comment