»
January 10, 2009
»

Using Singleton Pattern to Hide Static Globals

Objective-C has no class variables but they can be easily faked using C static global variable (and optionally +initialize) like this:

#import "Zeeba.h"

static NSString *gZeebaSomething;

@implementation Zeeba

+ (void)initialize
{
   gZeebaSomething = @"is here";
}

+ (NSString *)something
{
   return gZeebaSomething;
}

@end

The other approach would be creating another class (ZeebaSettings here), implement it as a singleton (using macro) and let it encapsulate global variable with all required logic:

// ZeebaSettings.h
  
#import <Cocoa/Cocoa.h>


@interface ZeebaSettings : NSObject {
   NSString *value;
}
@property(nonatomic, readonly, retain)NSString *value;

+ (ZeebaSettings *)sharedSettings;

- (id)init;

@end


// ZeebaSettings.m

#import "ZeebaSettings.h"
#import "AMSingleton.h"

@interface ZeebaSettings ()
@property(nonatomic, readwrite, retain) NSString *value;
@end

@implementation ZeebaSettings
@synthesize value;
AM_SINGLETON_BOILERPLATE(ZeebaSettings, sharedSettings)

- (id)init
{
   if(self = [super init]) {
      value = @"Hello world";
   }
   return self;
}

- (void)dealloc
{
   self.value = nil;
   [super dealloc];
}

@end

And now Zeeba can use ZeebaSettings singleton instance:

#import "Zeeba.h"
#import "ZeebaSettings.h"

@implementation Zeeba

+ (NSString *)something
{
   return [[ZeebaSettings sharedSettings] value];
}

@end

Still, one thing is missing — AMSingleton.h. It’s just a macro what adds boilerplate code for singleton pattern to work while following Apple recomendations:

#define AM_SINGLETON_BOILERPLATE(_className_, _accessorName_)                           \
  static _className_ *shared##_className_ = nil;                                        \
  + (_className_ *)_accessorName_                                                       \
  {                                                                                     \
    @synchronized(self) {                                                               \
      if(shared##_className_ == nil) {                                                  \
        [[self alloc] init];                                                            \
      }                                                                                 \
    }                                                                                   \
    return shared##_className_;                                                         \
  }                                                                                     \
                                                                                        \
  + (id)allocWithZone:(NSZone *)zone                                                    \
  {                                                                                     \
    @synchronized(self) {                                                               \
      if(shared##_className_ == nil) {                                                  \
        shared##_className_ = [super allocWithZone:zone];                               \
        return shared##_className_;                                                     \
      }                                                                                 \
    }                                                                                   \
    NSLog(@"Use +[%s %s] to access singleton instance", #_className_, #_accessorName_); \
    return nil;                                                                         \
  }                                                                                     \
                                                                                        \
  - (id)copyWithZone:(NSZone *)zone \
  {                                 \
    return self;                    \
  }                                 \
                                    \
  - (id)retain                      \
  {                                 \
    return self;                    \
  }                                 \
                                    \
  - (NSUInteger)retainCount         \
  {                                 \
    return NSUIntegerMax;           \
  }                                 \
                                    \
  - (void)release                   \
  {                                 \
  }                                 \
                                    \
  - (id)autorelease                 \
  {                                 \
    return self;                    \
  }

This is reblog from my older blog @ tumblr.

 
Internet Explorer 6
Are you serious?