Straybird’s Blog

A blog for life and study

Objective-C单例模式之ARC+GCD实现

单例模式是什么,这里姑且不谈,只谈谈ARC+GCD实现下单例模式比较特殊和受争议的点。

首先看一个ARC+GCD实现:

@interface Singleton : NSObject
+ (Singleton *)sharedInstance;     
@end     

@implementation Singleton     
static  Singleton *sharedInstance = nil ;             
+ (Singleton *) sharedInstance           
{      
    static dispatch_once_t onceToken;  // 锁      
    dispatch_once (& onceToken, ^ {     // 最多调用一次        
    sharedInstance = [[self alloc] init];         
    });      
    return  sharedInstance;            
}        
@end       

这个实现很简单,但是并不能防止用户通过[[Singleton alloc]init]创建多个实例,通过小小的测试即可:

Singleton *signleton1= [Singleton sharedInstance];       
NSLog(@"singleton1 is %@",signleton1);       
Singleton *signleton2= [[Singleton alloc]init];       
NSLog(@"singleton2 is %@",signleton2);       

可以看出多个实例被创建出来了。

怎么防止这一点呢?我们需要注意的几点:
1.Objective-c并不像C++那样,可以直接将构造函数设成private,使外部不能调用
2.只能考虑在alloc分配内存的时候把路给堵死
3.alloc中实际上调用了allocWithZone:,就算把alloc堵死了,也不能防止allocWithZone被用户直接调用
–>>所以我们必须通过allocWithZone将用户堵死

参考非ARC的实现,我们很容易写出如下所示的代码:

+(instanceType)allocWithZone:(struc _NZone)zone  
{  
    return [self sharedInstance];  
}    

但一运行,会发现程序hang住了。分析程序可知,程序在block中block住了。同样考虑到线程安全,allocWithZone的代码应该这样写:

+(instanceType)allocWithZone:(struc _NZone)zone  
{   
    static dispatch_once_t onceToken;  
    dispatch_once(&onceToken,^{  
    sharedInstance = [super allocWithZone:zone];
    });  
    return sharedInstance;   
}   

再运行之前的测试代码,这回单例只有一个了。

Comments