单例:
单例指一个唯一的,由全局共享的对象,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类
static A* g_ aObj=nil; (静态的模块变量)
满足单例的条件: 在整个程序的运行期间A类的对象的个数始终小于等于1
满足对象条件:1.有一块内存 2.对象是被初始化了的(只要把初始化函数设置为私有的方法,外界就不会任意的创建出单例对象了,属于第二个方法)
OC的解决办法:通过allocWithZone这个类方法,当用户反复调用alloc函数的时候,系统自动调用allocWithZone这个类方法,从而保证了只有一个单例对象(即限制了内存,属于对象的第一个方法,即用户获得的还是已经存在的单例的那块内存,alloc是失败的)
+(id)allocWithZone:(struct _NSZone *)zone //非线程安全的
{
if(g_aObj==nil)
{
g_aObj=[super allocWithZone:zone];
}
return g_aObj;
}
单例的线程安全问题:
如果有两个线程同时调用allocWithZone这个方法,线程a调用这个方法,当确认单例为nil的时候,系统把时间片切换给线程b,b这里单例也是nil,这样就会有两个单例,不满足但离得条件,所以加一个互斥锁从而达到线程安全的目的
//上锁
if(g_aObj==nil)
{
g_aObj=[super allocWithZone:zone];
}
return g_aObj;
//开锁
但是这样会有一个问题:每次调用都要上锁开锁(上开锁会有一定的性能损失,上锁开锁只有在A对象第一次实例化的时候起作用,A对象创建好之后就会远远存在内存中,if语句永远不成立,就不用再反复地上锁开锁)解决办法: double check机制
if(g_aObj==nil)
{
//上锁
if(g_aObj==nil)
{
g_aObj=[super allocWithZone:zone];
}
//开锁
}
return g_aObj;
double check机制等同于下面的方法:
if(g_aObj==nil)
{
@synchronized(g_aObj)
g_aObj=[super allocWithZone:zone];
}
return g_aObj;
解决方法2:
第一次调用某个类的+函数的时候,在这之前就会调用这个函数,第二次在调用+函数的时候就不会再调用这个方法(特有的单例免锁写法,同时是线程安全的)
+(void)initialize
{
g_aObj=[[A alloc]init];
}
下面是一个完整的单例的写法
@class A;
static A* g_aObj=nil;
@interface A:NSObject
{
@public
int _a;
}
@end
@implementation A
+(A*)shareAObj
{
if(g_aObj == nil)
{
@synchronized(g_aObj)
{
if(g_aObj == nil)
{
g_aObj=[[A alloc]init];
}
}
}
return g_aObj;
}
+(id)allocWithZone:(struct _NSZone *)zone
{
if(g_aObj == nil)
{
@synchronized(g_aObj)
{
g_aObj=[super allocWithZone:zone];
}
}
return g_aObj;
}
+(id)copyWithZone:(struct _NSZone *)zone
{
return g_aObj;
}
-(id)retain
{
return self;
}
-(id)autorelease
{
return self;
}
-(NSUInteger)retainCount
{
return UINT_MAX;
}
-(void)release
{
//do nothing
}
@end