美文网首页
iOS单例模式

iOS单例模式

作者: CyberDunk1997 | 来源:发表于2020-11-25 18:04 被阅读0次

    1. 利用@synchronized创建单例

    @implementation Singleton
    
    + (instancetype)shareInstance
    {
        static Singleton* single;
        @synchronized(self){
            if (!single) {
                single = [[Singleton alloc] init];
            }
        }
        return single;
    }
    
    @end
    

    ps:严格意义上来说,我们还需要将alloc方法封住,因为严格的单例是不允许再创建其他实例的,而alloc方法可以在外部任意生成实例。但是考虑到alloc属于NSObject,iOS中无法将alloc变成私有方法,最多只能覆盖alloc让其返回空,不过这样做也可能会让使用接口的人误解,造成其他问题。所以我们一般情况下对alloc不做特殊处理。系统的单例也未对alloc做任何处理

    2. 利用dispatch_once创建单例

    使用@synchronized虽然解决了多线程的问题,但是并不完美。因为只有在single未创建时,我们加锁才是有必要的。如果single已经创建.这时候锁不仅没有好处,而且还会影响到程序执行的性能(多个线程执行@synchronized中的代码时,只有一个线程执行,其他线程需要等待)。那么有没有方法既可以解决问题,又不影响性能呢?
    这个方法就是GCD中的dispatch_once

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

    2.1 dispatch_once原理

    dispatch_once为什么能做到既解决同步多线程问题又不影响性能呢?
    下面我们来看看dispatch_once的原理:
    dispatch_once主要是根据onceToken的值来决定怎么去执行代码。

    1. 当onceToken = 0时,线程执行dispatch_once的block中代码
    2. 当onceToken = -1时,线程跳过dispatch_once的block中代码不执行
    3. 当onceToken为其他值时,线程被线程被阻塞,等待onceToken值改变

    当线程首先调用shareInstance,某一线程要执行block中的代码时,首先需要改变onceToken的值,再去执行block中的代码。这里onceToken的值变为了140734731430192。
    这样当其他线程再获取onceToken的值时,值已经变为140734731430192。其他线程被阻塞。
    当block线程执行完block之后。onceToken变为-1。其他线程不再阻塞,跳过block。
    下次再调用shareInstance时,block已经为-1。直接跳过block。
    这样dispatch_once在首次调用时同步阻塞线程,生成单例之后,不再阻塞线程。dispatch_once是创建单例的最优方案

    参考

    作者:左忠飞
    链接:https://juejin.cn/post/6844903784100233230

    iOS 单例模式: https://www.jianshu.com/p/a92c0283f243

    相关文章

      网友评论

          本文标题:iOS单例模式

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