iOS之单例模式初探

单例模式多是设计模式中最简单的形式了,这一模式的意图就是使得类中的一个对象成为系统中的惟一实例。它提供了对类的对象所提供的资源的全局访问点。所以须要用一种只容许生成对象类的惟一实例的机制。下面让咱们来看下单例的做用:

  • 能够保证的程序运行过程,一个类只有一个示例,并且该实例易于供外界访问设计模式

  • 从而方便地控制了实例个数,并节约系统资源。安全

单例模式的使用场合

  • 类只能有一个实例,而且必须从一个为人数值的访问点对其访问。框架

  • 这个惟一的实例只能经过子类化进行拓展,而且拓展的对象不会破坏客户端代码。学习

在Objective-C中方法都是公有的,并且OC的语言自己是动态类型的,所以全部类均可以相互发送对方的消息。,而且Cocoa框架使用计数的内存管理方式来维护对象的内存中的生存期。
下面让咱们看一下OC当中的单例模式的写法,首先单例模式在ARC\MRC环境下的写法有所不一样,须要编写2套不一样的代码
  • 能够用宏判断是否为ARC环境spa

    #if _has_feature(objc_arc)#else//MRC#endif

    单例模式- ARC -方法一

  • ARC中单例模式的实现.net

  • 在 .m中保留一个全局的static的实例线程

 static id _instance; //重写allocWithZone:方法,在这里建立惟一的实例(注意线程安全)
 + (instancetype)allocWithZone:(struct _NSZone *)zone
{    @synchronized(self) {        if (_instance == nil) {
            _instance = [super allocWithZone:zone];
        }
    }    return _instance;
}
  • 提供1个类方法让外界访问惟一的实例设计

    + (instancetype)sharedInstanceTool{    @synchronized(self){        if(_instance == nil){
            _instance = [[self alloc] init];
        }
    }    return _instance;
}
  • 实现copyWithZone:方法指针

      -(id)copyWithZone:(struct _NSZone *)zone{  return _instance;
      }
    咱们在sharedInstanceTool,首先检查类的惟一实例是否已经建立,若是就会建立实例并将其返回。而之因此调用super而不是self,是由于已经在self中重载了基本的对象分配的方法,须要借用父类的功能来帮助处理底层内存的分配。
    allocWithZone:(struct _NSZone*)zone方法中,只是返回从sharedInstanceTool方法返回的类实例。而一样的在Cocoa框架中调用allocWithZone:(struct _NSZone*)zone会分配内存,引用计数会设置为1,而后返回实例。一样的重写(id)copyWithZone:(struct _NSZone *)zone方法,也是为了保证不会返回实例的副本,而是返回self.返回同一个实例。

方法二:

+(instancetype)sharedInstance {    static WMSingleton *singleton = nil;    if (! singleton) {
        singleton = [[self alloc] initPrivate];
    }    return singleton;
}

- (instancetype)init {    @throw [NSException exceptionWithName:@"这个是个单例"
                                   reason:@"应该这样调用 [WMSingleton sharedInstance]"
                                 userInfo:nil];    return nil;
}//实现本身真正的私有初始化方法- (instancetype)initPrivate {    self  = [super init];    return self;
}

上面这段代码中将singleton指针声明为静态变量。当某个定义了静态变量的方法返回时,程序不会释放相应的变量。####singleton变量的初始值是nil,当程序第一次执行sharedInstance方法时会建立一个对象,并将新建立的对象的地址赋值给singleton变量。当徐成再次执行sharedInstance方法时,不管多少次singleton变量仍然会指向最初那个建立的对象。由于指向对象的singleton变量是强引用的,而且程序永远不会释放该变量,因此singleton变量指向的对象也不会释放。

线程安全。

上面的实例中咱们经过@synchronized 来添加了一个互斥锁,以此来保证线程安全。而如今咱们开始尝试用线程的方式来实现一个加单的单例。

static WMObject *_instance;

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });    return _instance;
}

+ (instancetype)sharedInstance
{    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });    return _instance;
}

- (id)copyWithZone:(NSZone *)zone
{    return _instance;
}
从上面的代码咱们能够看到,实现的思路基本上也是一致的咱们在sharedInstanceTool,首先检查类的惟一实例是否已经建立,若是就会建立实例并将其返回。而略有不一样的地方就是咱们此次经过dispatch_once_t来保证线程的安全性。至于dispatch_once_t的用法这里就一一赘述了,线程的相关教程都会有其相关的描述。

到了这里一个简单的单例模式基本实现完成了,那么咱们能够尝试着把它封装到一个宏里,而后方便其之后的调用

建立一个WMSingleton.h

// .h文件#define WMSingletonH(name) + (instancetype)shared##name;

// .m文件#define WMSingletonM(name) 
static id _instance; 
+ (instancetype)allocWithZone:(struct _NSZone *)zone
 { 
     static dispatch_once_t onceToken; 
     dispatch_once(&onceToken, ^{
          _instance = [super allocWithZone:zone];
       });
     return _instance; 
 } 
 
 + (instancetype)shared##name 
 { 
    static dispatch_once_t onceToken; 
     dispatch_once(&onceToken, ^{ 
         _instance = [[self alloc] init];
      }); 
      return _instance;
 } 
   
 - (id)copyWithZone:(NSZone *)zone 
 {
     return _instance; 
 }
使用方法
//.h类//引入这个宏文件#import "WMSingleton.h"@interface WMObject : NSObjectWMSingletonH(object)@end//.m类@implementation WMObjectWMSingletonM(Car)@end

经过上面的演练咱们基本上学习了一些基本的单例模式而后在Cocoa Touch框架中一样存在着大量的单例模式让咱们来学习,好比UIApplicationUIAccelerometer、以及NSFileManager等等。因此在单例模式的学习上仍是依旧的任重道远呀。。。

相关文章
相关标签/搜索