Sunday, June 13, 2010

MyLogger Class in Objective-C (2)

Let's continue MyLogger class. In this l'll discuss the structure of MyLogger class. As I mentioned before, this class is based on Objectuser: A Single Class Logger in Objective C. To further enhance the logger class, I also wanted to add indention feature, which I have used in .Net: Debug class method Indent in System.Dianostics namespace.

Stucture of MyLogger Class

The structure of MyLogger class contains class level methods and properties, and instance level methods and properties. The following sections will discuss them in detail.

Class Level Methods and Properties

There actually only one class level method: Initialize. I think this is the default class initializer when any reference to MyLogger class is called or set. In theory, this method is not need to be called explicitly. As Objectuser's suggested, this method just creates a template, as a static instance of MyLogger, with default property settings.

All the class level properties are used for customized settings in all MyLogger instances. For example, defaultLogginLevel is used as default logger level. It is set only once and all the instances of MyLogger have the same logger level. Therefore, you can set this once at the begging of an application so that debug level is enabled or disabled. Other settings are very straightforward, such as indentChar, numberOfIndentChars, and format.

For the property format, it may need further explanation. The format should contain four place holders to be filed: indent, log level, context, and message. The default format is:

"%@[%@] %@ - %@"

where the first one is for indention, second for log level name (DEBUG, WARNING, ERROR, or INFO), third for context and last for log message.

Here are some codes:

// Define a static instnace as sort of prototype
static MyLogger* gInstance;
static int gIndent = 0;
static NSString* gFormat = @"%@[%@] %@ - %@"; // indent[logLevel] context - message
static char gIndentChar = ' ';
static int gIndentChars = 2;

#pragma mark -
#pragma mark MyLogger class methods
+ (void) initialize {
  // here self is class level self refert to the class ie MyLogger, best practice.
  gInstance = [[self alloc] init];
  gInstance.level = LogLevelError;

+ (int)defaultLoggingLevel {
  return gInstance.level;

+ (void)setDefaultLoggingLevel:(MyLoggerLevel)defaultLevel {
  gInstance.level = defaultLevel;

+ (char) indentChar {
  return gIndentChar;

+ (void) setIndentChar:(char)aChar {
  gIndentChar = aChar;

+ (int) numberOfIndentChars {
  return gIndentChars;

+ (void) setNumberOfIndentChars:(int)numberOfChars {
  gIndentChars = numberOfChars;

+ (NSString*) format {
  return gFormat;

+ (void)setFormat:(NSString *)aFormat {
  [gFormat autorelease];
  gFormat = [aFormat retain];

Instance Level Properties and NSObject Methods

There are two instance level properties: level and context. The level is corresponding to class property defaultLoggingLevel, but it provides flexibility for instance to set instance logging level. Those two properties are straightforward:

#pragma mark -
#pragma mark MyLogger properties
@synthesize level=mLevel;
@synthesize context = mContext;

I divide instance level methods into two groups: NSObject methods and MyLogger instance level methods. The NSObject methods are override methods, such as init and description. The init methods in MyLogger are actually two customized CTORs(constructors).

#pragma mark -
#pragma mark NSObject methods

- (id) initWithContext:(NSString*)loggingContext {
  if (self = [super init]) {
    self.level = gInstance.level;
    self.context = loggingContext;

  return self;

- (id) initWithContext:(NSString*)loggingContext logLevel:(MyLoggerLevel)intentLoggingLevel {
  if (self = [self initWithContext:loggingContext]) {
    self.level = intentLoggingLevel;

  return self;

- (NSString*) description {
  NSString* s = [[NSString alloc] initWithFormat:@"Mylogger instance - level: %@, context: %@",
     nameOfLevel(mLevel), mContext];
  [s autorelease];
  return s;

The description method may not be required. It just occurred to me with crashing within MyLogger class once and the description provides me some help to identity MyLogger class with its internal private data member information.

There is another one NSObject related method: dealloc. I called it as memory management. It contains very simple codes:

#pragma mark -
#pragma mark Memory management

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

My next blog will focuse on MyLogger instance methods.