iOS单例模式和NSZone小结

关于单例模式(Singleton),我们可能并不陌生。今天就简单介绍一下iOS的单例模式(Singleton),并且总结一下使用单例模式的时候需要注意的一些问题。

单例模式是一个类在系统中只有一个实例对象。通过全局的一个入口点对这个实例对象进行访问。在iOS开发中,单例模式是非常有用的一种设计模式。

下面的链接是关于单例模式的详细介绍:http://en.wikipedia.org/wiki/Singleton_pattern

iOS SDK中也有许多类使用了单例模式,例如,UIApplication:当程序启动的时候,会调用UIApplicationMain方法,在该方法中,会实例化一个UIApplication对象,之后在程序中的任意地方调用sharedApplication方法都将返回一个与当前应用程序相关的UIApplication实例(UIApplicationMain方法中创建的UIApplication单例)。

什么时候使用单例模式?在程序中,单例模式经常用于只希望一个类只有一个实例,而不运行一个类还有两个以上的实例。当然,在iOS SDK中,根据特定的需求,有些类不仅提供了单例访问的接口,还为开发者提供了实例化一个新的对象接口,例如,NSFileManager可以通过defaultManager方法返回相同的一个NSFileManager对象。如果需要新的一个NSFileManager实例对象,可以通过init方法。

单例模式的实现方法:

单例模式官方文档推荐的有两种实现方法:

第一种如下:

+ (Singleton *)instance { 
if (!instance) { 
    instance = [[super allocWithZone:NULL] init]; 
} 
    return instance; 
} 
+ (id)allocWithZone:(NSZone *)zone { 
    return [[self instance] retain]; 
} 

第二种如下:

+ (MySingleton *)sharedInstance {
 
    @synchronized(self) {
        if (sharedInstance == nil) {
                        sharedInstance = [[MySingleton alloc] init];
                }
    }
 
    return sharedInstance;
}
 
+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;  // assignment and return on first allocation
        }
    }
    return nil; // on subsequent allocation attempts return nil
}

但是在我们的工程中,有很多单例模式,是直接只写了下面的方法:

@implementation Singleton  
static Singleton *instance = nil;  
+ (Singleton *)sharedInstance  {  
   @synchronized(self)   
   {  
        if(!instance) {  
           instance = [[Singleton alloc] init];  
        }  
    }  
   
    return instance;  
}  
 @end

上面这种做法其实是很不安全的。在实现单例模式的时候,我们需要实现以下几个方法:

// 当第一次使用这个单例时,会调用这个init方法。
- (id)init
{
    self = [super init];
 
    if (self) {
        // 通常在这里做一些相关的初始化任务
    }
 
    return self;
}
 
// 这个dealloc方法永远都不会被调用--因为在程序的生命周期内容,该单例一直都存在。(所以该方法可以不用实现)
-(void)dealloc
{
    [super dealloc];
}
 
// 通过返回当前的sharedInstance实例,就能防止实例化一个新的对象。
//在实现单例模式的时候,这个方法最好还是要实现,因为如果有其他人试图不通过sharedInstance方式而是通过alloc方式去实现一个对象的时候,可能会造成多个实例被创建。而重写allocWithZone方法,可以用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例。
+ (id)allocWithZone:(NSZone*)zone {
    return [[self sharedInstance] retain];//或者 return [self instance]; 
} 
// 同样,不希望生成单例的多个拷贝。
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
 
// 什么也不做——该单例并不需要一个引用计数(retain counter)
- (id)retain {
    return self;
}
 
// 替换掉引用计数——这样就永远都不会release这个单例。
- (NSUInteger)retainCount {
    return NSUIntegerMax;
}
 
// 该方法是空的——不希望用户release掉这个对象。
- (oneway void)release {
 
}
 
//除了返回单例外,什么也不做。
- (id)autorelease {
    return self;
}

以上的这些方法,我们在实现单例模式的时候,最好还是要实现一下,可以避免单例使用不当带来的一些问题。

以上是单例模式需要注意的一些内容。下面简单介绍一下NSZone相关的知识。

我们在alloc或者copy一个对象的时候,经常会看到如下方法:

+(id) allocWithZone:(NSZone *)zone
+ (id)copyWithZone:(NSZone *)zone

如果我们实现一下这两个方法,会发现,我们在alloc或者copy的时候,会调用以上方法。所以在上文,我们为了防止单例类被重复创建,重载了上面两个方法。

所以最开始我以为zone是一个对象,但是这种想法是错误的!zone不是一个对象!它是一个难懂的C结构,被用于记录关于内存处理(管理)一系列对象的信息。

NSZone 是苹果对内存分配和释放的优化方式。NSZone不是一个对象;它是一个难懂的C结构,它被用于纪录关于内存处理(管理)一系列对象的信息。

你几乎不需要担忧你自己的应用(applications)是怎样管理你自己的空间(zones)的Cocoa透明地管理它。默认的NSZone在程序启动和所有对象被分配时创建。所以你为什么想要去用你自己的NSZone呢?

如果你大量分配数百个小对象,事实上你会发现你花费精力来为他们分配内存是有意义的。因为这种标准的(默认的)空间会被一直使用,它会变得斑驳起来;释放对象的过程会给整个内存留下令人尴尬的空隙。标准空间的分配器(allocator)也知道知道这一点,所以它尝试着优先去使用被用户释放的内存,去填补这些空隙,但是这种方式只有在空间(zone)变得很大时才有明显效果。

如果你想为大量对象分配内存,然后,你可以创建你自己的空间(zone)并且告诉它不用去为了为新对象分配内存而去查找那些空隙。分配器现在能够每次跳到内存分配的末尾为你的新对象分配内存,能起到不错的效果。

另外,分配器也能为你节省时间,当分配器向操作系统请求更多内存时,分配器去查找哪块空间什么时候被填满,需要花费不少时间。一种更快的时间是一次去请求一大块内存,你也能告诉你的NSZone在这儿做什么。

NSZone也能节省你释放内存的时间。它有方法释放大量分配的内存,而不打扰释放器(deallocators)。如果用一个集合(set)包含一系列对象,这样能够节省时间,你可以一次释放它们而不用去乏味地一个个释放它们。

你可能感兴趣的:(iOS单例模式和NSZone小结)