iOS 三种创建单例的方法

1>. 什么是单例
单例模式是一种常用的软件设计模式。在它的核心结构中包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果系统在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
2>. 单例用处
应用场景:在程序中类只初始化一次的时候用单例方法,单例类在内存中只创建一次 / 确保程序运行期某个类,只有一份实例,用于进行资源共享控制。
优势:
使用简单,延时求值,易于跨模块
iOS的系统中用到的一些单例

[UIApplication sharedApplication];
[NSUserDefaults standardUserDefaults];
[NSURLCache sharedURLCache];

一、iOS单例的创建

1>. 单线程单例
单例类需要保证只有一个实例,因此在第一次访问这个实例的时候才创建,之后访问直接取已经创建好的实例

// 单线程单例
+(instancetype)sharedLoadData
{
    static YYSingleton *singleteon;
    if (!singleteon ) {
    singleteon = [[YYSingleton alloc] init];
    }
    return singleteon;
}

单线程单例存在一些弊端,在多线程的情况下,会产生线程不安全的情况。严格意义上来说,我们还需要把alloc方法变为私有方法才行,严格的单例是不允许再创建其他实例的,而alloc方法可以在外部任意生成实例。但是考虑到alloc属于NSObject,iOS中无法将alloc变成私有方法,最多只能覆盖alloc让其返回空。不过个人不建议这么做,一般情况下对alloc不做特殊处理。系统的单例也未对alloc做任何处理

2>. @synchronized单例
上面单线程单例,在多线程情况下,可能会出现一些问题。如果两个线程同时调用shareInstanc,可能会创建出2个singleton出来。所以在对多线程情况下,我们需要使用@synchronize来加锁

// @synchronized单例
+(instancetype)sharedLoadData
{
    static YYSingleton *singleton;
    @synchronized (self) {
    if (!singleton) {
        singleton = [[YYSingleton alloc] init];
    }
    }
    return singleton;
}

加锁以后,当多个线程同时调用shareInstance时,由于@synchronized已经加锁,只能有一个线程创建singleton实例。这样就解决了多线程调用单例的问题。

3>. dispatch_once单例
使用@synchronized虽然一定程度上解决了多线程的问题,但并不完美。因为只有在singleton未创建时,加锁才是必要的。如果singleton已经创建,这个时候还加锁的话,会影响性能。
在iOS中,GCD为我们提供方便又高效的方法—dispatch_once

 +(instancetype)sharedLoadData
{
    static YYSingleton *singleton = nil;

    static dispatch_once_t onceToken;
    // dispatch_once  无论使用多线程还是单线程,都只执行一次
    dispatch_once(&onceToken, ^{

        singleton = [[YYSingleton alloc] init];
    });
    return singleton;
}

dispatch_once为什么能做到既解决同步多线程问题

dispatch_once的原理:
dispatch_once主要是根据onceToken的值来决定怎么去执行代码。
1.当onceToken = 0时,线程执行dispatch_once的block中代码
2.当onceToken = -1时,线程跳过dispatch_once的block中代码不执行
3.当onceToken为其他值时,线程被阻塞,等待onceToken值改变
当线程调用shareInstance,此时onceToken = 0,调用block中的代码,此时onceToken的值变为140734537148864。当其他线程再调用shareInstance方法时,onceToken的值已经是140734537148864了,线程阻塞。当block线程执行完block之后,onceToken变为-1.其他线程不再阻塞,跳过block。下次再调用shareInstance时,block已经为-1.直接跳过block。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值