Lingo Gringo and Not Forgetting One’s “self”.

In my last iDevBlogADay post I wrote about my goal to get Lingo Gringo ready for AppStore submission. After that post, I met up with another Colorado local (http://davidwparker.com) and impulsively declared that I would have Lingo Gringo ready by today, this 29th of March, 2011.  What a challenge!  So, after weeks wrestling with memory issues and hidden crash-causing bugs, I have finally gotten a functional Lingo Gringo.  The problem:  I am still several (about a dozen.5) features behind submission readiness.

So, the primary bug that really had me going (much to my embarrassment), was a simple memory management problem.  You can rest assured that I have since been studying up on the subject, but here’s the problem I was having:

-(id)initWithFirstWord:(NSString *)theFirstWord SecondWord: (NSString *)theSecondWord {
  self = [self init];
  if (self) {
      firstWord	= theFirstWord;
      secondWord = theSecondWord;
  }
  return self;
}

So what’s the big deal? Well, thanks to some pointers (pun intended) from the guys over at Stanford, I discovered the importance of including ‘self’ before assigning my variable, otherwise I’m just setting the pointer to the same location as my ‘theFirstWord’ or ‘theSecondWord’ variable. Thanks to Brett and Fabio in the comments, I’m reminded to mention that in my header file I was declaring the ‘firstWord’ and ‘secondWord’ properties as retained like this:


@property (nonatomic, retain) NSString *firstWord;

@property (nonatomic, retain) NSString *secondWord;

It’s because of the ‘retain’, that by adding ‘self’ in the implementation file, I release whatever my ‘firstWord’ object is.  Then, ‘firstWord’ points to my ‘theFirstWord’ object and retains it. So, with the ‘self’, I can access Apple’s ‘built-in’ retain and release functionality!

So, my fix ended up looking like the following, and my headache was able to be replaced by other similar frustrations:

-(id)initWithFirstWord:(NSString *)theFirstWord SecondWord: (NSString *)theSecondWord {
  self = [self init];
  if (self) {
      self.firstWord = theFirstWord;
      self.secondWord = theSecondWord;
  }
  return self;
}

The moral of this story: Don’t forget your ‘self’s.

So in the end, Lingo Gringo is now well on its way to AppStore submission (and sure success) as I finish up with the remaining features and polishing up!

UPDATE: Thanks to @atnan, I have updated my code to call [self init] instead of [super init], as I’m not overriding NSObject’s init method, but rather building my own particular initWithFirstWord:SecondWord: method. Thanks, @atnan!

This post is part of iDevBlogADay, a group of blogs by indie iPhone developers featuring two posts per day. You can subscribe to iDevBlogADay through RSSor follow the #iDevBlogADay hash tag or @idevblogaday on Twitter.

6 Responses to Lingo Gringo and Not Forgetting One’s “self”.

  1. As a side note, objects are not automatically retained by using self
    self.firstWord = theFirstWord;

    You must be sure to declare your property as (retain)
    @property (retain) NSString * firstWord;

    By default, they use assign (which sets the variable, but does not retain).
    As well, always make sure to release any properties you have marked as retain in the classes dealloc method

    • Thanks for pointing that out, you’re absolutely correct! I forgot to mention that, but I’ve updated the post now.

  2. That is a very important tip! Just as a reminder though: that will only work if “firstWord” and “secondWord” are declared as properties with the retain keyword, as such:

    @property (readonly, retain) NSString *firstWord;

    • It looks like you and Brett both caught the same ‘retain’ omission in my post, but I’ve updated it now. Thanks for pointing that out and for stopping by!

  3. Hi Chad,

    Hopefully I explained the designated initialiser convention correctly — it’s hard to explain such things 140 characters at a time :-). In general, always think twice if you’re calling a method on super that doesn’t match the signature of the current method being called (i.e. calling init from initWithFirstWord:secondWord:).

    As for the rest of your tip — it’s somewhat frowned upon to use accessors in your designated initialiser (and dealloc, for that matter). When you use “self.firstWord = theFirstWord”, you’re actually calling “[self setFirstWord:theFirstWord]”. If a subclass overrides “- setFirstWord:”, you’re calling a method on an object that’s in an inconsistent state which can lead to strange results.

    In practical terms, this means you should use “firstWord = [theFirstWord retain]” instead of “self.firstWord = theFirstWord” in your initialiser.

    Cheers,

    Nathan de Vries

    • Yes, the 140 character limit was frustrating, but I finally got what you were talking about. :) Thanks again for all that.

      As for the accessors in my initializer, I do see your point and I agree, which makes much of the practical application of my post questionable, but I’ll revise that.
      All of the examples I have seen out there, have used accessors, but I’m beginning to be more conscious of the affects that will be had on possible subclassing instances.

      So, in my revised code, I am using the “firstWord = [theFirstWord retain]” and then releasing “theFirstWord” after I return self, is there a better place to put that?

      -Chad

Leave a Response