Saturday, July 30, 2011

One singleton to rule them all

One of the most common design patterns is the singleton. However, implementing singletons, especially in Objective-C, can be very repetitive. I often forget how to properly override all the memory management methods and need to look up a previous singleton. One of the goals of programming is to automate the repetetive, mundane tasks. Cocoa With Love has a great synthesized singleton made from a C pre-processor macro. The problem with this is that it's not flexible. So, I made an Objective-C singleton that can be dropped in any project. By subclassing RBSingleton you can gain all the benefits of a singleton without adding any further code and you have full flexibility to customize each subclass.

There are two main parts that make RBSingleton possible. First, it stores all the singleton instances in a class-wide dictionary. A singleton typically keeps a static pointer to the singleton instance. This works fine as long as it's not subclassed. When subclasses become involved, the subclass that allocates first defines the singleton instance for all subclasses. This restriction is normally beneficial to singletons, but breaks with subclassing. I could have required subclasses to provide a pointer to a static class pointer through a method call, but this imposes more on the subclass's implementation than I wanted. By using a class-wide dictionary, every subclass can store its singleton instance under a unique key. To guarantee a unique key, I simply use the subclass's name.

Second, the singleton instance is allocated by dynamically calling NSObject's -allocWithZone: method as shown below.

Method allocMethod = class_getClassMethod([NSObject class], @selector(allocWithZone:));
sharedInstance = [
method_invoke(self, allocMethod, nil) initialize];

The trick here was to allocate the singleton as the class of the RBSingleton subclass but use NSObject's -allocWithZone: method to do so. This is similar to calling [super allocWIthZone:nil];. The difference is that it's jumping more than one level in the inheritance hierarchy. This is known as a grandsuper call. The Objective-C dynamic runtime makes it possible to make such a call. You will also notice that I hardcoded [NSObject class] into the code. I could have dynamically discovered the root class with the following code:

+ (Class)rootClass {

        
Class rootClass = nil;
        
Class currentClass = [self class];

        
while ((currentClass = class_getSuperclass(currentClass)))
                rootClass = currentClass;

        
return rootClass;
}


If I instead needed to get a grandsuper class that isn't necessarily the root class and I know a subclass of the grandsuper I could use simpler code like this:

[RBSingleton superclass];

Since I know the specific grandsuper class I need, I hardcoded it for efficiency. If you use RBSingleton and find a need to dynamically discover a particular grandsuper class, you can use the above code to do so. I've uploaded RBSingleton as a Gist and you can find it here.

One last note, to use RBSingleton you need to include libobjc.dylib for the dynamic runtime calls.

Tuesday, July 26, 2011

#define Abuse

Lately I've been encountering some terrible Objective-C code, and I have a few words to say about it. One of the first problems I've found is the overuse of #define. Don't get me wrong, #define has its place, but when it comes to constants #define should not be the first choice.

Anti-Patterns
One of the problems with #define is that it's simply a macro substitution. There is generally no type associated with the value. This makes is harder for the compiler to warn you of potential errors. Macros can also have side effects you may forget about. For example:

#define MY_STRING_CONSTANT [[NSString alloc] initWithFormat:@"Hello World!"] // Very bad.

The above example will cause a memory leak unless you remember to release the value each time. Just a side note, Apple's static analyzer will pick up this error if you turn it on. I should also mention that the following, related example is not preferable. I have actually seen this used in production code before.

#define MY_STRING_CONSTANT [NSString stringWithFormat:@"Hello World!"] // Still not great.

Numbers
With a couple anti-patterns out of the way, let's go over the proper way to define constants. You will find that it doesn't take much more effort to properly define constants. Numbers are the simplest and one of the most common, so we'll start with them. In your .m file (applies to .c or .cpp too) you will define your constant like the following:

const NSInteger kMyInt = -100;
const NSUInteger kMyUnsignedInt = 42;
const CGFloat kMyFloat = 3.14;

You could instead use 'int', 'unsigned int', and 'float' if you prefer, but the above types are generally the preferred data types. If you want to keep your constant visible to just your implementation file, then you are done. If not, you need to do one last thing. In your header file, you will need to use the following:

extern const NSInteger kMyInt;
extern const NSUInteger kMyUnsignedInt;
extern const CGFloat kMyFloat;

The reserved word 'extern' makes a promise to the compiler. You are letting the compiler know that you are not defining the value right away, but at link time, that value will exist. In this case, it's defined in your implementation file. With that in place, you are now done; your constant is defined and other classes can #import (#include for C and C++) your header file and use your number constants.

You may wonder why you can't define the constant right in your header file. If you do, you will get an error message that looks like this: "ld: duplicate symbol <Constant Name> in <File 1> and <File 2>." Generally #import handles duplicate imports properly; however, it doesn't work for constants. I figure this error is why developers unaware of 'extern' default to #define.

Enumerations
Closely related to numbers are enumerations. If you ever have a series of related number constants, you probably want an enum. For example:

// A contrived example but should get the idea across.
enum {
        kJanuary = 1,
        kFebruary = 2,
        kMarch = 3,
        kApril = 4,
        kMay = 5,
        kJune = 6,
        kJuly = 7,
        kAugust = 8,
        kSeptember = 9,
        kOctober = 10,
        kNovember = 11,
        kDecember = 12,
};

Enumerations are great for bit masks too.

// Another contrived example.
enum {
        kBit1 = 1 << 0,
        kBit2 = 1 << 1,
        kBit3 = 1 << 2,
        kBit4 = 1 << 3,
};

Enumerations are where type checking really helps. Say you are using a switch statement, the compiler can warn you if you didn't include one of your enum values as a switch case.

Strings
Strings are also very common in Cocoa programming. There is one extra detail that makes them different from numbers. At first you may want to make a constant like this:

const NSString * kMyString = @"Hello World!"; // Wrong - String Anti-Pattern 1

This is wrong for a couple different reasons. First, NSString is immutable, meaning that it can't be changed. This essentially makes it a constant by default. However, there is a big flaw with the above anti-pattern. I will first show the proper way:

NSString * const kMyString = @"Hello World!"; // Right

At first glance, you are probably wondering why 'const' is next to the constant name. The difference between the number and string examples is that the NSString is a pointer. The first string example tells the system that the value @"Hello World!" can't change, but the pointer value can change. You probably wouldn't, but you could do the following:

kMyString = @"Goodbye World!"; // Very bad, but allowed in String Anti-Pattern 1.

You didn't change the value of @"Hello World!", but you did change what kMyString pointed to. That doesn't sound like a constant at all.

By the way, the following is also permissible, but wrong.

const NSString * const kMyString = @"Hello World!"; // Wrong - String Anti-Pattern 2

This makes both the value and the pointer constant. However, the first 'const' changes the data type of the constants. None of the Cocoa frameworks accept a const NSString * (since it's redundant). This means that you will have a compiler warning anytime you try to pass your constant to a Cocoa framework method. You might do something similar with other objects, but in Objective-C, such cases should be very rare. This is something more common in C or C++.

Objects
Objects other than strings can be a little more tricky. You can't do the following:

MyObject * const kObject = [[MyObject alloc] init]; // Wrong - Object Anti-Pattern 1

The problems is the right-hand side does not evaluate to a compile time constant. Furthermore, if it was possible, it would be difficult to configure the object properly. This requires a different technique.

// Right
+ (MyObject *)MyConstObject {

        static MyObject * obj = nil;

        if (!obj) {
                obj = [[MyObject alloc] init];

        // Any other initial setup.
        }

        return obj;
}

Looking at the return type of MyObject *, you may think this has the same problem that String Anti-Pattern 1 had. This is not the case here. The original constant pointer is protected within the method; it can't be changed externally. When you call the method, you receive a copy of the object's address. You can change it if you want, but it won't affect anyone else. Naively you may want to change the return type to MyObject * const, but a const pointer doesn't affect the data type. You could do the following regardless:

MyObject * obj = [[self class] MyConstObject]; // Type MyObject * is the same as MyObject * const

One last note about object constants is that they are technically memory leaks. However, they are permissible for the same reason that singletons are permissible. What's more interesting is that Apple's latest static analyzer now flags singletons as memory leaks but still doesn't catch the above constant.

When to use #define
I should probably include a kind word about #define. If you want to use any pre-processor macros such as #if or #ifdef, then #define is your only choice. #define is also good for simple, inline functions or when you want to write some code that will do automatic renaming (see Cocoa With Love's synthesized singleton). #define has countless valuable uses, but when it comes to constants, try something else first.

Tuesday, July 19, 2011

Driving Technical Change Review

One particular book that caught my eye some time ago is Driving Technical Change by Terrence Ryan. In his book, Ryan teaches the skills necessary to convince others to adopt your ideas. Though the book focuses around technical fields, most of the skills taught apply to other disciplines.

Summary
Ryan begins his book by classifying different types of people, such as the Cynic, the Uniformed, and the Irrational. From there he progresses to the skills needed to use on the different categories including delivering your message, gaining trust, and getting publicity. Ryan then concludes with how to strategically employ the needed skills.

Pros
The book is written in a way that it can in whatever order fits your needs. Once you have identified the category (or categories) of people you are working with, you can jump straight to the recommended skills and techniques. The chapters are short and easy to read. Every skeptic category and rhetoric technique includes short examples to illustrate the ideas.

Most of the ideas covered seem common sense. Yet there are some examples that I had never thought of employing. For example, Ryan suggests one way to get coworkers to accept a framework you've built is to open source it. If many people start using it, or even contributing to it, then your coworkers will be much more open to using your framework.

Cons
Ryan tends to dodge confronting the Irrational. It is true that little can be done to convince an irrational person. However, he doesn't offer many suggestions besides avoid them and/or have management mandate a policy. Management mandate may be the silver bullet, but what about the situation when management is irrational? Perhaps the best solution at that point is to find a new job.

Before reading this book, I was expecting Ryan to go into more detail on leadership skills. However, many skills such as gaining trust are left with few examples or explanation of how to gain trust. I do like the succinctness of Ryan's writing, but sometimes I'm left wanting more concrete examples.

Recommendation
If you are one of the many that feel your voice isn't heard, this book likely has some skills you haven't tried yet. Ryan shares his secret to leadership: "you can be promoted to management, but no one appoints you a leader." Driving Technical Change can help you take initiative and become a leader.

You can purchase Driving Technical Change here from The Pragmatic Bookshelf.