正确单例的创建方法--Singleton设计模式

创建单例必须注意的3个要点

  1. 一是某个类只能有一个实例
  2. 二是它必须自行创建这个实例
  3. 三是它必须自行向整个系统提供这个实例

    使用单例(Singleton)的2个优点:

    1.实例控制:Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例。
    2.灵活性:因为类控制了实例化过程,所以类可以更加灵活修改实例化过程

————————-方法1(别用)————————
01 首先创建一个继承于NSObject的一个单例类,这里以 Instance.h为例。
具体的讲解都在代码注释中,不一一瞎比比了:

在Instance.h文件中

#import <Foundation/Foundation.h>
@interface Instance : NSObject

//声明一个单例类方法
+ (id)sharedInstance;

@end

02 在 Instance.m 文件中:

#import "Instance.h"

@implementation Instance

//定义静态全局变量
static Instance *instance = nil;

//单例类方法实现
+ (id)sharedInstance {

    //判断是否为空,若为空,创建
    if (instance == nil) {

        //创建单例
        instance = [[self alloc] init];
    }

    //返回实例
    return instance;

}

@end

这样一个简单的单例就完成了,但是,为了说一下为何不推荐这个方法,我们接着在控制器 ViewController.m文件中演示一下。

03 在 ViewController.m 中

#import "ViewController.h"
#import "Instance.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    Instance *instance1 = [Instance sharedInstance];
    NSLog(@"单例1的地址为:%@", instance1);

    Instance *instance2 = [Instance sharedInstance];
    NSLog(@"单例2的地址为:%@", instance2);

    Instance *instance3 = [[Instance alloc] init];
    NSLog(@"单例3的地址为:%@", instance3);


}

@end

打印结果:

这里写图片描述

从打印结果可以发现:单例1和单例2的打印地址一样,而单例3的地址不同,原因是什么呢?很简单,第3中的单例对象获取的方式是重新创建了一个单例实例,也就是说系统又alloc了一块内存空间。而真正的获取一个单例实例我们通常用的是[Instance sharedInstance],并且单例只能有一个实例对象。当然,既然存在问题,那必然有解决的办法,所以为了防止用户有时获取单例不慎采用了alloc的方法,这里推荐相当好的一个单例创建方法,看下面。

———————-方法2(正确的单例创建写法)—————————–
04 同样,在Instance.h文件中

#import <Foundation/Foundation.h>

@interface Instance : NSObject

//声明一个单例类方法
+ (id)sharedInstance;

@end

05 在 Instance.m 文件中:

#import "Instance.h"

@implementation Instance

//定义静态全局变量
static Instance *instance = nil;

//单例的创建方法2
//多线程创建单例(推荐使用)
+ (id)sharedInstance {

    //静态单例令牌,用作标识
    //使用dispatch保证只创建一次,会自动加锁!如果使用其他方法创建的话,需要**自己加锁**!
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        //创建单例,调用父类,并初始化
        instance = [[super allocWithZone:nil] init];

    });

    //返回单例实例
    return instance;
}

//防止外部调用alloc,复写系统自带的alloc方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone {

    //返回当前类的单例
    return [self sharedInstance];
}
@end

注:为了防止用户使用关键字copy导致单例不唯一,还需要重写:copyWithZone方法!!!

06 在 ViewController.m 中,同03,这里就不写了,重点看一下打印结果:

这里写图片描述

显然,尽管在控制器中的打印内容和方法1中的一样,但打印结果却是不同,这里打印的三种结果中的地址相同,也就是说获取到的是同一个单例实例对象。所以,为了防止用户使用 Instance *instance3 = [[Instance alloc] init]; 这样的alloc创建获取单例实例对象方法,推荐使用方法2多线程创建单例. 当然,网上还有很多创建单例的方法,大家可以尝试比较一下哪种更好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值