ObjectiveC单例

本文详细解析了单例模式的概念及其在程序开发中的应用,通过对比传统实现方式与官方推荐做法,深入剖析了单例模式的可靠性问题,并提出了克服相关障碍的方法。同时,介绍了单例模式在多线程环境下的安全性处理策略,旨在为开发者提供更加稳健的单例对象实现方案。
其实对于单例,在程序开发中非常的常见。
最近我也对单例进行了一些更细致的研究。
在我的程序中,单例一般是这么去写的:
+ (DataSource *)shareInstance
{
    static DataSource *instance = nil;
    if (instance == nil)
    {
        instance = [[DataSource alloc] init];
    }
    return instance;
}


在我做过的十几个软件中,一直都是这么去写的。
但是在我前段时间看书的过程中,发现跟书中的例子不太一样,所以做了一下研究。


发现,这样的单例是不可靠的。因为如果开发者一直调用 [DataSource shareInstance] 当然没有问题, 但是如果有人调用 [ DataSource alloc] 这样的方法,就会出现多个对象。
所以,我们需要实现“严格”意义的单例。


需要克服两个障碍:
1. 发起调用的对象不能以其他分配方式实例化单例对象。
2.对单例对象实例化的限制应该与引用计数内存模型共存。


下面我们看一下官方给出的单例模式的例子


static MyGizmoClass *sharedGizmoManager = nil;  
  
+ (MyGizmoClass*)sharedManager  
{  
    if (sharedGizmoManager == nil) {  
        sharedGizmoManager = [[super allocWithZone:NULL] init];  
    }  
    return sharedGizmoManager;  
}  
  
+ (id)allocWithZone:(NSZone *)zone  
{  
    return [[self sharedManager] retain];  
}  
  
- (id)copyWithZone:(NSZone *)zone  
{  
    return self;  
}  
  
- (id)retain  
{  
    return self;  
}  
  
- (NSUInteger)retainCount  
{  
    return NSUIntegerMax;  //denotes an object that cannot be released  
}  
  
- (void)release  
{  
    //do nothing  
}  
  
- (id)autorelease  
{  
    return self;  
}


他的方式是重写release,retain,retainCount,autoRelease,allocWithZone和copyWithZone等方法。
1 重写allocWithZone和copyWithZone的目的是外部在多次调用alloc的时候,内部能够确保对象只创建了一次。
2 重写release、retain、autorelease、retainCount避免单件对象被外部释放。


两个缺点:
A 隐藏了在对象生命周期管理时出现的bug。
    对对象的引用出错的原因必然是程序本身的错误,隐藏对象的引用计数错误就是隐藏了应用程序的错误。
    从工程角度上讲,崩溃要比程序的逻辑错误容易定位。
    解决方法:建议在release、retain、autorelease里面做一些内部的调用次数监控,一旦发现外部调用不平衡就发出警告。
B 对象可以被多次init。
    多次调用init导致错误的可能性还是有的,这种错误包括重复加载某些资源降低性能。
    解决方法:重写init并在内部判重就可以了。
C 多线程安全
    解决方法:在sharedManager中加入同步代码块,代码:


+ (MyGizmoClass*)sharedManager  
{  
    @synchronized(self) {  
        if (sharedGizmoManager == nil) {  
            sharedGizmoManager = [[super allocWithZone:NULL] init];  
        }  
    }  
    return sharedGizmoManager;  
}  
顾名思义,模式的特点就是保证一个类仅有一个实。因为这个模式只和一个类有关,没有类与类之间的关系,所有就给出图示了。那么还是先说一下基本的定义。 模式(Singleton),保证一个类仅有一个实,并提供一个访问它的全局访问点。 通常我们可以让一个全局变量使得一个对象被访问,但它能防止你实化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实。这个类可以保证没有其他实可以被创建,并且它可以提供一个访问该实的方法。平时,我们常用模式的地方通常是多线程。 因为Objective C传承了Smalltalk语言,所以在Objective C中实现模式和C++和C#以及Java都太一样。因为要保证类型对象的一性,所以就要考虑Objective C在实化对象时候的各种方式。因为在Objective C中创建的各个类型都继承自NSObject类型,所以我们需要考虑NSObject类型里实化的方法,下面让我们展开来说。 在Objective C的实化对象的方式主要有三种,分别如下: obj = [NSObject new]; obj = [[NSObject alloc]init]; obj = [[NSObject allocWithZone]init]; NSObject类参考文档里记录第三种方法是因为历史原因遗留下来的,在当前的Objective C中已经再使用,所以我们就考虑这种方式了。下面让我们主要看一下前两种方式。 第一种方式,用new方法初始化其实是第二种方式的总和,当调用new方法时,其实是先调用了alloc方法进行isa(is a pointer)操作,创建指针,指向内存中的数据结构,紧接着调用了init方法对数据进行初始化,NSObject类参考文档里也有具体的说明,大家也可以查看文档,具体实现方式随后我会用代码向大家进行展示。 第二种方式看起来就很明确了,先调用alloc创建指针指向内存中的数据结构,再调用init方法初始化数据。这里需要注意的是,init方法只是起到了初始化数据的作用,其实也可以自定义初始化方法,即完全可以自定义一个普通返回NSObject类型的方法来代替init方法,即init方法是可以随意被代替的。只过NSObject类型中new方法默认会调用init方法而已,init方法可以看作是NSObject类型的默认构造函数。 所以综上所述,其实只有alloc方法是每次必须调用的方法,那么我们只要控制住alloc方法,对此方法进行覆盖就可以保证类型对象的一性了。好了,说了这么多,让我们看看如何实现吧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值