Singleton Design Pattern

January 11, 2012 under Cocoa, Design Patterns

A singleton is an object class designed such that only one instance of that class will ever exist. This can be useful to minimize resources required (e.g., database connections) or ensure consistent data throughout an application (e.g., user preferences).

With the advent of automatic reference counting (ARC) in Objective-C, a lot of memory management has changed (for the better). The transition from manual reference counting to ARC is generally straightforward (there is even a refactoring tool in Xcode to speed the process), but some changes require a bit more work (and understanding). If you have implemented a singleton class, for example, you will see a number of errors in the ARC refactor preview.

Manual Reference Counting

I will begin with the manual reference counting approach. The general structure here is outlined in the Apple Documentation as well, but has not been updated (to the best of my knowledge) for ARC.

Listing: SomeFactory.h

@interface SomeFactory : NSObject

@property (nonatomic, retain) NSMutableArray * collection;

+ (SomeFactory *)defaultFactory;

@end

The theory here is to override any method that might result in the allocation of a new object of the singleton class. The normal memory management methods (retain, release, and retainCount) are overridden since there should always be a retain count of 1 for the Singleton object. The NSUIntegerMax value returned by the retainCount() method is designed to provide a hint that a singleton is being used.

Listing: SomeFactory.m

#import "SomeFactory.h"

static SomeFactory *defaultFactory = nil;

@implementation SomeFactory

@synthesize collection;

+ (LibraryFactory *)defaultFactory
{
   if (! defaultFactory)
   {
      defaultFactory = [[super allocWithZone:NULL] init];
   }
   return defaultFactory;
}

+ (id)allocWithZone:(NSZone *)zone
{
   return [self defaultFactory];
}

- (id)init
{
   if (defaultFactory) return defaultFactory;
   
   [super init];
   
   collection = [[NSMutableArray alloc] init];
   
   return self;
}

- (id)retain
{
   return self;
}

- (oneway void)release
{
   
}

- (NSUInteger)retainCount
{
   return NSUIntegerMax;
}

@end

In summary, you create a static instance and always return that static instance. If no instance yet exists, create it.

Automatic Reference Counting (ARC)

Under ARC, you neither implement nor call retain, release, autorelease, or retainCount. For autorelease, under some circumstances, you might create an @autoreleasepool structure. After removing forbidden methods, as well as making your singleton thread safe, you have the following.

Listing: SomeFactory.h

@interface SomeFactory : NSObject

@property (nonatomic, strong) NSMutableArray * collection;

+ (SomeFactory *)defaultFactory;

@end

Listing: SomeFactory.m

#import "SomeFactory.h"

static SomeFactory *defaultFactory = nil;

@implementation SomeFactory

@synthesize collection;

+ (SomeFactory *)defaultFactory
{
   @synchronized([SomeFactory class]) {
      if (! defaultFactory) {
         defaultFactory = [[SomeFactory alloc] init];
      }
   }
   return defaultFactory;
}

- (id)init
{
    if (self = [super init]) {
        collection = [[NSMutableArray alloc] init];
    }
    return self;
}

@end

Add Frameworks in Xcode 4

May 13, 2011 under Cocoa, iOS

A lot has changed in Xcode 4. As I recently worked on implementing some web services, I needed to add the libxml2 library to my project.

Add a Framework

Frameworks are now managed under build phases for the application target

  1. Project: Choose the "Project Navigator" from the Jump Bar or choose the View > Navigators > Project menu item
  2. Target: Click on the target in the navigator panel (it is the top item signified by the Xcode icon)
  3. Build Phases: Click on the "Build Phases" in the tab control on the main window
  4. Libraries: Expand "Link Binary With Libraries" and click the "+" button to add a framework
  5. libxml: Use the search field to find libxml (I chose libxml2.2.7.3.dylib) and click the "Add" button

Make Headers Available

For a standard framework (like AddressBookUI.framework), I would be already done. But when working with C libraries (like libxml), I also need to make the headers available to my project.

  1. Build Settings: In the same place, choose the "Build Settings" tab control in the main window
  2. All Filter: Make sure the "All" filter is selected in the subnavigation (as opposed to "Basic"
  3. Search Path: Find and expand "Search Paths"
  4. Header Search Path: Find and expand "Header Search Paths" and click the "+" button for Debug
  5. libxml: Enter /usr/include/libxml2
  6. Release: Repeat the last two steps for Release