Objective-C 單例巨集

canopus4u發表於2015-09-15

實現

先貼出程式碼
也可以直接訪問我的github:RWSingleton

#import <objc/runtime.h>

#define RW_DECLARE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(classname, accessorMethodName) 
+ (classname *)accessorMethodName;

#if __has_feature(objc_arc)
    #define RW_SYNTHESIZE_SINGLETON_RETAIN_METHODS
#else
    #define RW_SYNTHESIZE_SINGLETON_RETAIN_METHODS 
    - (id)retain 
    { 
        return self; 
    } 
    
    - (NSUInteger)retainCount 
    { 
        return NSUIntegerMax; 
    } 
    
    - (oneway void)release 
    { 
    } 
    
    - (id)autorelease 
    { 
        return self; 
    }
#endif

#define RW_SYNTHESIZE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(classname, accessorMethodName) 

static classname *accessorMethodName##Instance = nil; 

+ (classname *)accessorMethodName 
{ 
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
        accessorMethodName##Instance = [super allocWithZone:NULL]; 
        accessorMethodName##Instance = [accessorMethodName##Instance init]; 
        method_exchangeImplementations(
                class_getInstanceMethod([accessorMethodName##Instance class], @selector(init)),
                class_getInstanceMethod([accessorMethodName##Instance class], @selector(init_once)));
    });
    return accessorMethodName##Instance; 
}

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

- (id)copyWithZone:(NSZone *)zone 
{ 
    return self; 
} 
- (id)init_once
{ 
    return self; 
} 
RW_SYNTHESIZE_SINGLETON_RETAIN_METHODS

#define RW_DECLARE_SINGLETON_FOR_CLASS(classname) RW_DECLARE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(classname, shared##classname)
#define RW_SYNTHESIZE_SINGLETON_FOR_CLASS(classname) RW_SYNTHESIZE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(classname, shared##classname)

使用

例如你需要一個名為MyOjbect的單例. 在MyOjbect.h中,程式碼如下:

#import "RWSingletonMacro.h"
@interface MyObject : NSObject
RW_DECLARE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(MyObject, sharedObject)
@end

MyObject.m中:

#import "MyObject.h"
@implementation MyObject
RW_SYNTHESIZE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(MyObject, sharedObject)
@end

注意

很多時候,單例都會擁有自己的instance varible,所以這裡做了method siwwizling, 你可以過載
-(id)init,在其中實現你的初始化邏輯.MyObject.m看起來如下:

#import "MyObject.h"
@implementation MyObject
RW_SYNTHESIZE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(MyObject, sharedObject)

- (id) init
{
  self = [super init];
  //do your things
  return self
}
@end

此外,從實現中可得知,即便是如下程式碼也可以保證obj是單例。

MyObject* obj = [[MyObject alloc] init];

原作寫於segmentfault 連結

相關文章