美文网首页iOS启蒙iOS学习开发iOS学习笔记
iOS 设计模式: Singleton – 单例模式

iOS 设计模式: Singleton – 单例模式

作者: 孟豊Mike | 来源:发表于2017-02-19 23:56 被阅读62次

    单例 的意思就是确保在程序运行过程中只创建一个对象实例,而可以被多次使用。如我们常见的网络请求类、工具类、和其他管理类等。作为一个iOS开发者,我们经常和单例打交道,比如:[NSUserDefaults standerUserDefaults], [UIApplication sharedApplication],[UIScreen mainScreen], [NSFileManager defaultManager]返回的都是单例对象。
    我们在开源项目、苹果示例代码能见到无数使用单例的例子。Xcode 甚至有默认的 "Dispatch Once" 代码片段,使我们可以非常简单地在代码中添加一个单例。

    "Dispatch Once" 代码片段

    一、单例的作用

    • 它可以保证某个类在程序运行过程中最多只有一个实例,节省内存开销。如果某个对象需要被多个其它对象使用,那可以考虑使用单例,因为这样该类只使用一份内存资源。

    注意点!!!! 单例应该只用来保存全局的状态,并且不能和任何作用域绑定。如果这些状态的作用域比一个完整的应用程序的生命周期要短,那么这个状态就不应该使用单例来管理。因为单例从创建后到彻底关闭程序前都会一直存在,如果过多的创建单例无疑浪费系统资源和影响系统效率

    二、单例的三要点

    • 单例模式的三个要点:

    1. 该类有且只有一个实例;(类的构造方法是私有的我们只需要重写allocWithZone方法,让初始化操作只执行一次)

    2. 该类必须能够自行创建这个实例;(类提供一个类方法产生对象)

    3. 该类必须能够自行向整个系统提供这个实例。(类中有一个私有的自己对象我们可以在.m文件中定义一个属性即可)

    三、单例的实现步骤

    1. 为单例对象创建一个静态实例,可以写成全局的,也可以在类方法里面实现,并初始化为nil;
      2. 提供一个类方法,方便外界访问;
      3. 重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例;
      4. 重写-copyWithZone方法和-MutableCopyWithZone方法

    一般创建对象的步骤分为申请内存(alloc)、初始化(init)这两个步骤,我们要确保对象的唯一性,所以要在第一步拦截它。当我们调用alloc方法时,oc内部会调用allocWithZone这个方法来申请内存,我们覆写这个方法,然后在这个方法中调用shareInstance方法返回单例对象,这样就可以达到我们的目的。拷贝对象也是同样的原理,覆写copyWithZone方法,然后在这个方法中调用shareInstance方法返回单例对象。

    #import "Tools.h"
    
    @implementation Tools
    // 创建静态对象 防止外部访问
    static Tools *_instance;
    +(instancetype)allocWithZone:(struct _NSZone *)zone
    {
        @synchronized (self) {
            // 为了防止多线程同时访问对象,造成多次分配内存空间,所以要加上线程锁
            if (_instance == nil) {
               _instance = [super allocWithZone:zone];
          }
          return _instance;
    }
    // 为了使实例易于外界访问 我们一般提供一个类方法
    // 类方法命名规范 share类名|default类名|类名
    +(instancetype)shareTools
    {
        //return _instance;
        // 最好用self 用Tools他的子类调用时会出现错误
        return [[self alloc]init];
    }
    // 为了严谨,也要重写copyWithZone 和 mutableCopyWithZone
    -(id)copyWithZone:(NSZone *)zone
    {
        return _instance;
    }
    -(id)mutableCopyWithZone:(NSZone *)zone
    {
        return _instance;
    }
    
    
    也可以使用Xcode 默认的dispatch_once代码片段用 GCD的方式创建:
    @implementation Singleton
    static id _instance;
    
    + (instancetype)allocWithZone:(struct _NSZone *)zone{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
        return _instance;
    }
    
    + (instancetype)sharedSingleton{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [[self alloc] init];
        });
        return _instance;
    }
    
    - (id)copyWithZone:(NSZone *)zone{
        return _instance;
    }
    @end
    

    四、使用单例的注意事项

    • 单例给我们带来方便的同时也有一定的副作用,因为单例对象一旦创建,对象指针是保存在静态区的,单例对象在堆中分配的内存空间只有在程序终止后才会释放,过多的单例必定会增大我们消耗的内存
    • 不要做断开单例类对象与类中静态引用的危险操作。
    • 多线程使用单例使用共享资源时,注意线程安全问题。

    相关文章

      网友评论

        本文标题:iOS 设计模式: Singleton – 单例模式

        本文链接:https://www.haomeiwen.com/subject/wwdqwttx.html