2009 Archives

SOLID Class Design: The Dependency Inversion Principle

— Category: Software Design

This is part four of a five part series about SOLID class design principles by Robert C. Martin. The SOLID principles focus on achieving code that is maintainable, robust, and reusable. In this post, I will discuss the Dependency Inversion Principle.

The Dependency Inversion Principle (DIP): High level modules should not depend upon low level modules. Both should depend upon abstractions.

SOLID Class Design: The Liskov Substitution Principle

— Category: Software Design

This is part three of a five part series about SOLID class design principles by Robert C. Martin. The SOLID principles focus on achieving code that is maintainable, robust, and reusable. In this post, I will discuss the Liskov Substitution Principle.

The Liskov Substitution Principle (LSP): functions that use pointers to base classes must be able to use objects of derived classes without knowing it.

Why Inline Comments Are Generally a Bad Idea

— Category: Coding Style/Conventions

Bellow is a single function commented in two different ways. Which one is better?

NSString* MD5StringOfString(NSString* inputStr)
{
    //UTF8 encoding is used so the hash can be compared with hashes of ASCII strings
    NSData* inputData = [inputStr dataUsingEncoding:NSUTF8StringEncoding];

    unsigned char outputData[CC_MD5_DIGEST_LENGTH];
    CC_MD5([inputData bytes], [inputData length], outputData);

    NSMutableString* hashStr = [NSMutableString string];
    int i = 0;
    for (i = 0; i < CC_MD5_DIGEST_LENGTH; ++i)
        [hashStr appendFormat:@"%02x", outputData[i]];
 
    return hashStr;
}
NSString* MD5StringOfString(NSString* inputStr)
{
    //convert the string to UTF8 encoded byte data
    NSData* inputData = [inputStr dataUsingEncoding:NSUTF8StringEncoding];

    //calculate the hash
    unsigned char outputData[CC_MD5_DIGEST_LENGTH];
    CC_MD5([inputData bytes], [inputData length], outputData);

    //convert hash to a hexadecimal string
    NSMutableString* hashStr = [NSMutableString string];
    int i = 0;
    for (i = 0; i < CC_MD5_DIGEST_LENGTH; ++i)
        [hashStr appendFormat:@"%02x", outputData[i]];
 
    //return the hexadecimal string
    return hashStr;
}

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:

Implementing Your Own Cocoa Bindings

— Category: Cocoa

This post is the result of investigation into a stackoverflow.com question of mine.

So, you’ve created a spiffy NSView of your own, and have decided to make it compatible with bindings. Great! So you go and read the documentation, and you look at mmalc’s GraphicsBindings examples. You override bind:toObject:withKeyPath:options: and everything works. But wait! Why isn’t the NSWindowController ever being deallocated anymore?

Now you’ve got a nasty retain cycle on your hands. You do a little research and discover that not only do other people have the same problem, but even Apple’s bindings used to have it a few years ago. How did Apple fix the problem? With the magic, undocumented class NSAutounbinder, which nobody seems to know much about.

Other people will tell you that you don’t need to override bind:toObject:withKeyPath:options: and that bindings work automatically. This is only a half truth. NSObject does provide an implementation of bind:toObject:withKeyPath:options:, but it only half works. Using the default NSObject implementation, changes in the model will update the view, but the reverse is not true. When the bound property of the view changes, nothing happens to the model.

So, what is a Cocoa developer to do? I’ll explain how to implement your own bindings that work exactly like Apple’s, with no retain cycles. I haven’t found this solution anywhere else, so as far as I know, I’m the discoverer. I feel so special. It has been mentioned before at least once. The solution is hard to find, though.

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.

Model View Controller Explained

— Category: Software Design

Model view controller (MVC) is a very useful and popular design pattern. If you’re writing software, you should know it. Unfortunately it’s also one of the hardest to truly understand. In this article I will provide what I think is the simplest explanation of MVC, and why you should use it.