Category: Coding Tips

When A Café Is Not A Café – A Short Lesson In Unicode Featuring NSString

— Category: Coding Tips

Let's start with two exotic strings (console output is in the code comments):

NSString* apples = NSGetFrenchWord();
NSString* oranges = NSGetFrenchWord();

NSLog(@"apples == '%@'", apples); 
//apples == 'café'
NSLog(@"oranges == '%@'", oranges); 
//oranges == 'café'

They look identical, but looks can be deceiving.

NSLog(@"isEqual? %@", [apples isEqual:oranges] ? @"YES" : @"NO");
//isEqual? NO
NSLog(@"[apples length] == %lu", [apples length]);
//[apples length] == 4
NSLog(@"[oranges length] == %lu", [oranges length]);
//[oranges length] == 5

Const Correctness For NSString (And Pointers In General)

— Category: Coding Tips

So you're implementing a new notification and you want the name to be a constant. Easy, right?

const NSString* VTMyNewNotification;

If that's how you do constants, you're not doing it quite right. Try assign a new value to the alleged constant and watch in horror as the compiler doesn't stop you.

This is because when you type const NSString*, the compiler interprets that as a pointer to a constant NSString. NSString is already an immutable object, so making a constant NSString doesn't do anything except maybe cause some compiler errors/warnings later when you try to use it. What you're really after is a constant pointer to an NSString. It's ever so subtly different, and written like so:

NSString* const VTMyNewNotification;

Don't feel bad. It's a common mistake. I used to do it until Rob Napier schooled me, and now I'm passin' on the learnin' to you.

Coding Tip: Replace Complicated Conditions With Boolean Variables

— Category: Coding Tips

Consider the following if statement:

if(dragOperation != NSDragOperationCopy && NSPointInRect(currentMouseLocation, self.bounds)){
    //do something
}

Even though you may have worked out what the condition represents, it probably took you a little longer than it should. It's complicated, making it time consuming to read, and prone to bugs upon modification. Thankfully, there is an easy remedy:

Coding Tip: Have A Single Exit Point

— Category: Coding Tips

Having one exit point (return) from a function is a good thing. Here is an example of a single exit point:

int MyArray::indexOfElement(int elementToFind){
  int foundIndex = ELEMENT_NOT_FOUND;

  for(int i = 0; i < m_numberOfElements; ++i){
    if(this->elementAtIndex(i) == elementToFind){
      foundIndex = i;
      break;
    }
  }

  return foundIndex;
}

Having multiple exit points can be bad. Here is an example of multiple exit points:

int MyArray::indexOfElement(int elementToFind){
  for(int i = 0; i < m_numberOfElements; ++i){
    if(this->elementAtIndex(i) == elementToFind){
      return i;
    }
  }

  return ELEMENT_NOT_FOUND;
}

The main reason multiple exit points are bad is that they complicate control flow. The more complicated the control flow is, the harder the code is to understand. The harder the code is to understand, the greater the change of introduction bugs whenever the code is modified.