Objective-C设计模式——单例Singleton,对象创建

单例

和其它语言的单例产不多,可以说是最简单的一种设计模式了。但是有几个点需要注意下,单例就是一个类只有一个实例。

所以我们要想办法阻止该类产生别的实例,一般语言中都会将构造函数写为private。但是OC中的函数并没有限定符,所以我们需要用一些小技巧来屏蔽这一点。

应用场景

类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法。

这个唯一的实例只能通过类的子类化进行扩展,而且扩展的对象不会破坏客户端代码。

注意

1.OC中单例的实例变量要定义在.m文件

2.OC中单例需要重载allocWithZone:和copyWithZone:方法来防止创建别的实例。

3.单例创建要注意线程安全,不然就可能出现多个实例。

注意问题将会在Demo中讲解

Demo

首先先来看一个最常规,的不严谨的单例实现:

@implementation Singleton

static Singleton *sharedInstance;

-(Singleton *)sharedInstance
{
    if(sharedInstance)
    {
        sharedInstance = [Singleton new];
    }
    return sharedInstance;
}

@end

这看似好像是可以得到单例对象了,但是这可以说是单例的一种变形。绝不能说这就是单例,因为我们可以轻松地通过其他方式来创建对象。

所以我们还要我修改allocWithZone:和copyWithZone:方法(alloc 和 copy 方法实际上就是调用这两个方法)

-(id)copyWithZone:(NSZone *)zone
{
    return [[self class] sharedInstance];
}

+(id)allocWithZone:(struct _NSZone *)zone
{
    return [self sharedInstance];
}

可是这就出现另一个问题,在sharedInstance方法里面我们实际调用过allocWithZone:(new 调用 alloc),但是它的alloc被我们重写了,这就会出现错误。所以我们需要修改sharedInstance方法

+(Singleton *)sharedInstance
{
    if(sharedInstance)
    {
        sharedInstance = [[super allocWithZone:NULL] init];
    }
    return sharedInstance;
}

这样就可以顺利的返回单例了,而且无法通过其它方式产生实例对象。

看似完美了实际还会有问题出现,因为现在是非线程安全的,可能存在同一时间创建多个实例的情况,所以修改如下

+(instancetype)sharedInstance
{
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        sharedInstance = [[super allocWithZone:NULL] init];
    });
    return sharedInstance;
}

客户端代码如下:

        Singleton *singleton = [Singleton sharedInstance];
        Singleton *singleton2 = [[Singleton alloc] init];
        Singleton *singleton3 = [singleton copy];
 
        [singleton print];
        [singleton2 print];
        [singleton3 print];

输出结果:

2015-07-21 21:10:32.797 Singleton[42537:10347987] 0x7fff5fbff7a8
2015-07-21 21:10:32.798 Singleton[42537:10347987] 0x7fff5fbff7a8
2015-07-21 21:10:32.798 Singleton[42537:10347987] 0x7fff5fbff7a8

可以看到内存都指向了同一地址。