iOS单例模式的实现方法总结

来源:互联网 发布:usb网络打印服务器使用 编辑:程序博客网 时间:2024/06/07 19:33
  • 概念
单例(Singleton):保证一个类只有一个实例,并提供一个对该实例的全局访问点。

“严格”单例的条件:
(1)不管用什么方法,只能创建一个实例;
(2)线程安全: 多个线程访问同一段代码,每次运行结果都是一样,而非不确定的;
(3)与iOS引用计数的内存管理模型兼容。

  • 实现方法
方法1:
     static MySingletonClass *sharedSingleton = nil;
  + (MySingletonClass*)defaultSingleton
  {
  @synchronized(self) //线程同步
     {
          if (sharedSingleton == nil) 
             {
                      //因为已经在self中重载了基本的对象分配方法,所以这里要用super,否则会发生循环调用
         sharedSingleton = [[super allocWithZone:NULL] init];
         }
  }
  return sharedSingleton;
  }

      //重载的方法,保证任何时候全局只存在一个单例,而且不会被销毁
  + (id)allocWithZone:(NSZone *)zone
  {
  return [self defaultSingleton];
  }

  - (id)copyWithZone:(NSZone *)zone
  {
  return self;
  }

  - (id)retain
  {
  return self;
  }

  - (unsigned)retainCount
  {
  return UINT_MAX; //denotes an object that cannot be released
  }

  - (void)release
  {
  //do nothing
  }

  - (id)autorelease
  {
  return self;
  }

说明:iOS中object是通过 allocWithZone:(NSZone *)zone 方法实现对象的内存分配,然后返回对象,并置retainCount为1。其中zone 可以想象成一个内存池,alloc,allocWithZone或是dealloc这些操作,都是在这个内存池中操作的。cocoa总是会配置一个默认的NSZone,任何默认的内存操作都是在这个“zone”上操作的。默认的NSZone的缺陷在于,它是全局范围的,时间一长,必然会导致内存的碎片化,如果你需要大量的alloc一些object,那么性能就会受到一些影响。所有cocoa提供方法,你可以自己生成一个NSZone(实际上就是我上面的demo那样,重写allocWithZone方法就行了),并将alloc, copy全部限制在这个”zone“之内。
alloc实际是调用allocWithZone:NULL。

方法2:
利用apple的GCD技术。GCD(Grand Central Dispatch)是Apple开发的一个多核编程的解决方法。

GCD中有这样一个函数:void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block),其中第一个参数predicate,该参数是检查后面第二个参数所代表的代码块是否被调用的谓词,第二个参数则是在整个应用程序中只会被调用一次的代码块。dispach_once函数中的代码块只会被执行一次,而且还是线程安全的。

+(MySingletonClass *) defaultSingleton

{

static MyClass *sharedSingleton;

static dispatch_once_t once;

dispatch_once(&once,^{

sharedEntity = [[MySingletonClass alloc] init];

});

return sharedSingleton;

}

注意:使用上面例子来实现的单例是“伪单例”,也就是说只有当使用者用MySingletonClass *obj = [MySingletonClassdefaultSingleton];方式来取得对象时候才算是单例,但是我们无法阻止编程者直接使用alloc来创建自己的对象。 


  • 单例的子类化

对于方法1创建的单例,如果不加修改的子类化MySingleton,返回的实例总是MySingleton本身,因为MySingleton重载了所有实例化相关的方法,所以对其子类化需要特别的技巧。我们可以使用一些Foundation框架中的函数,根据类的类型实例化任何对象。其中一个是id NSAllocateObject(Class aClass, NSUInteger, extraBytes, NSZone *zone),第一个参数是要实例化的类的类型;第二个是用于索引的实例变量的额外字节数,它总是0;第三个参数用于指定内存分配的区域,它一般为NULL,表示默认区域。通过指定类的类型,这个函数可以实例化任何对象。

如果用这个函数来创建单例,那么会变成这样:


+(MySingletonClass)defaultSingleton
{
@synchronized(self) 
{
      if (sharedSingleton == nil) 
         {
                      //因为已经在self中重载了基本的对象分配方法,所以这里要用super,否则会发生循环调用
         sharedSingleton = [NSAllocateObject([self,class], 0, NULL)  init];
     }
}
return sharedSingleton;
}
0 0