• OC中两种单例实现方式


    OC中两种单例实现方式

    写在前面
    前两天探索了一下C++ 的单例,领悟深刻了许多。今天来看看OC中的单例又是怎么回事。查看相关资料,发现在OC中一般有两种实现单例的方式,一种方式是跟C++ 中类似的常规实现方法,另一种是利用GCD来实现的。接下来分别看看这两种单例实现方式是怎么做的

    常规实现

    与C++中的相似,在OC中实现单例需要满足以下条件:

    1. 设计一个私有的构造方法

    2. 设计一个私有的,本类的对象

    3. 设计一个类方法,作为2中类对象的全局访问点
      接下来我们逐个解决上述3个条件。
      首先,将构造函数设计为私有的。在OC中,对象的创建包括两个步骤:内存申请(alloc)和初始化(init)。也就是说,如果我们希望构造函数私有,那么我们要自己定义alloc方法,使得每次调用该方法,都返回条件2中的对象。在OC中,调用alloc时,alloc实际上是调用allocWithZone这个方法来申请内存的,因此,我们在设计单例的时候,要重写这个方法。另外,我们还要保证使用copy复制单例中的对象时,返回的也是步骤2中的对象,而不会重新创建,因此,我们还要重写copyWithZone这个方法。具体代码如下
      .h文件:

    //
    //  Singleton.h
    //  Singleton
    //
    
    #import <Foundation/Foundation.h>
    
    @interface Singleton : NSObject
    
    //类方法
    + (Singleton *) getInstance;
    
    @end
    

    .m文件

    //
    //  Singleton.m
    //  Singleton
    //
    
    #import "Singleton.h"
    
    @implementation Singleton
    
    //在.m文件中声明静态的类实例,不放在.h中是为了让instance私有
    static Singleton* instance = nil;
    
    //提供的类唯一实例的全局访问点
    //跟C++中思路相似,判断instance是否为空
    //如果为空,则创建,如果不是,则返回已经存在的instance
    //不能保证线程安全
    +(Singleton *) getInstance{
        if (instance == nil) {
            instance = [[Singleton alloc] init];//调用自己改写的”私有构造函数“
        }
        
        return instance;
    }
    
    //相当于将构造函数设置为私有,类的实例只能初始化一次
    +(id) allocWithZone:(struct _NSZone*)zone
    {
        if (instance == nil) {
            instance = [super allocWithZone:zone];
        }
        return instance;
    }
    
    //重写copy方法中会调用的copyWithZone方法,确保单例实例复制时不会重新创建
    -(id) copyWithZone:(struct _NSZone *)zone
    {
        return instance;
    }
    
    @end
    

    main函数文件

    //  main.m
    //  Singleton
    //
    
    #import <Foundation/Foundation.h>
    #import "Singleton.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            //用getInstance方法创建实例1、2并打印内容
            Singleton *singleton1 = [Singleton getInstance];
            NSLog(@"singleton1 = %@.", singleton1);
        
            Singleton *singleton2 = [Singleton getInstance];
            NSLog(@"singleton2 = %@.", singleton2);
            
            //用alloc+init创建实例3并打印内容
            Singleton *singleton3 = [[Singleton alloc] init];
            NSLog(@"singleton3 = %@.", singleton3);
    //用alloc+init创建实例4,打印copy后的内容 Singleton *singleton4 = [[Singleton alloc] init]; NSLog(@"singleton4 = %@.", [singleton4 copy]); } return 0; } /

    结果
    enter description here

    可以看到,所有的是咧地址都是相同的,也就是或,返回的是同一个地址

    GCD方式的单例

    GCD是苹果提供的一种多线程的实现方案。使用GCD,用户不用手动管理线程的生命周期,非常方便。GCD提供了一个多线程下,一段代码只被执行一次的方式:dispath_once。这种方式是线程安全的。代码如下,(其余代码与常规方式相同,不再复制)

    //使用gcd中的dispatch_once()方法,函数的第二个参数是一个代码段,告诉gcd我们要做的事情是什么 
    +(Singleton *) getInstance{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[self alloc]init];
        });
        return instance;
    }
    
    //使用gcd的dispatch_once()方法,在传入的代码段中,调用父类的内存申请函数
    +(id) allocWithZone:(struct _NSZone*)zone
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [super allocWithZone:zone];
        });    return instance;
    }
    

    结果如下:
    enter description here

    这个结果也证明了,最后创建的类的实例只有一个

  • 相关阅读:
    Object中的线程等待和Condition
    synchronized锁和Lock锁
    手写二叉排序树(二叉查找树、二叉搜索树)
    JDK源码之ArrayList-Iterator
    JDK源码之ArrayList
    Integer&int,自动装箱&自动拆箱
    学习Zookeeper第一课
    Thumbnailator处理图片
    线程的停止和中断
    BigInteger和BigDecimal
  • 原文地址:https://www.cnblogs.com/scut-linmaojiang/p/5299207.html
Copyright © 2020-2023  润新知