美文网首页
iOS-单例的正确写法

iOS-单例的正确写法

作者: 下班不写程序 | 来源:发表于2020-03-31 18:00 被阅读0次

一、OC 中创建单例的几种方式

1.1 单线程模式单例

/// 单线程模式单例
+ (instancetype)sharedInstance{
    
    static Singleton *singleton = nil;
    if(!singleton){
        
        singleton = [[Singleton alloc] init];
    }
    return singleton;
}

存在的问题就是: 只能在单线程中使用, 一旦有多线程同时调用sharedInstance, 就会创建多个singleton对象, 如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    dispatch_queue_t dispatchQueue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t dispatchGroup = dispatch_group_create();
    dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
        Singleton *s1 = [Singleton sharedInstance];
        NSLog(@"%@",s1);
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
        Singleton *s2 = [Singleton sharedInstance];
        NSLog(@"%@",s2);
    });
    dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){
        NSLog(@"全部执行完毕.");
    });
}

打印结果:
2020-03-31 16:34:19.548777+0800 OC中的单例[37254:1422273] <Singleton: 0x6000008e0680>
2020-03-31 16:34:19.548780+0800 OC中的单例[37254:1422270] <Singleton: 0x6000008f4520>
2020-03-31 16:34:19.562469+0800 OC中的单例[37254:1422085] 全部执行完毕.

1.2 通过@synchronized加锁的多线程单例

+ (instancetype)sharedInstance {
    
    static Singleton *singleton;
    @synchronized (self) {
        
        if (!singleton) {
            singleton = [[Singleton alloc] init];
        }
    }
    return singleton;
}

存在的问题就是: 只有在singleton未创建时, 加锁才是必要的, 如果singleton已经创建, 这个时候还加锁的话,反而会影响性能.

1.2 GCD多线程方式实现单例

+ (instancetype)sharedInstance {
    
    static dispatch_once_t onceToken;
    static Singleton *singleton;
    dispatch_once(&onceToken, ^{
        singleton = [[Singleton alloc] init];
    });
    return singleton;
}

注: dispatch_once 无论使用多线程还是单线程,都只执行一次, 在安全的前提下也保证了性能, 是官方推荐的方式.

dispatch_once 主要是根据onceToken 的值来决定怎么去执行代码。
1.当onceToken=0时,线程执行dispatch_once的block中代码
2.当onceToken=-1时,线程跳过dispatch_once的block中代码不执行
3.当onceToken为其他值时,线程被阻塞,等待onceToken值改变

dispatch_once 执行的流程
1.当线程调用shareInstance,此时onceToken = 0,调用block中的代码。 此时onceToken的值变为140734537148864。
2.当其他线程再调用shareInstance方法时,onceToken的值已经是140734537148864了,线程阻塞。
3.当block线程执行完block之后,onceToken变为-1.其他线程不再阻塞,跳过block。
4.下次再调用shareInstance时,block已经为-1.直接跳过block。

1.3 团队开发情况下的单例的封装

当团队进行开发的时候, 创建对象的方法也可能就各不相同, 但是为了保证对象的唯一性, 需要:

// 当static 关键字修饰局部变量时,只会初始化一次且在程序中只有一份内存
static Singleton* _singleton = nil;

+ (instancetype)sharedInstance {
    
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        
        _singleton = [[super allocWithZone:NULL] init] ;
/**
 1. 不使用alloc 方法,而是调用[[super allocWithZone:NULL] init]
 2. 已经重载allocWithZone 基本的对象分配方法,所以要借用父类(NSObject)的功能来帮助出处理底层内存分配
 3. 如果_singleton = [self alloc] init];创建的话,将会和allocWithZone产生死锁。dispatch_once中的onceToken线程被阻塞,等待onceToken值改变。
 */
    }) ;
    return _singleton ;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    return [Singleton sharedInstance];
}

// 须遵守 NSCopying 协议
- (id)copyWithZone:(NSZone *)zone{
    return [Singleton sharedInstance];
}

// 须遵守 NSMutableCopying 协议
- (id)mutableCopyWithZone:(NSZone *)zone{
    return [Singleton sharedInstance];
}

二、Swift 中的单例

格式: Swift 中单例的格式和 Swift中懒加载的方式类似
1.懒加载格式:
- lazy var 名称: 类型 = 类型()
- lazy var 名称: 类型 = { return 类型() }()
2.单例格式
- static let xxx: 类型 = 类型()
- static let xxx: 类型 = { return 类型() }()

2.1 Swift 中的单例写法一

import UIKit

class Singleton: NSObject {

    // static:静态的 let: 常量 -> 全局访问点
    static let shared: Singleton = Singleton()
}

2.1 Swift 中的单例写法二

import UIKit

class Singleton: NSObject {

    static let shared2: Singleton = {
        let singleton = Singleton()
        // 可以做一些 初始化、自定义的操作
        return singleton
    }()
}

.End

相关文章

  • iOS-正确单例的写法

    前言 单例应该是iOS中很简单的设计模式,写个单例很简单很方便。网上例子也很多,大家也是基本上copy下来就可以了...

  • iOS-单例的正确写法

    一、OC 中创建单例的几种方式 1.1 单线程模式单例 存在的问题就是: 只能在单线程中使用, 一旦有多线程同时调...

  • 单例模式 Singleton Pattern

    单例模式-菜鸟教程 iOS中的设计模式——单例(Singleton) iOS-单例模式写一次就够了 如何正确地写出...

  • Android中常见的内存泄漏汇总

    1.单例模式的错误写法 单例模式的正确写法: 2.非静态内部类创建静态实例造成的内存泄漏错误写法 正确写法:将该内...

  • 单例的正确写法

    之前有次面试 人家问起单例我就这么写了个 结果被人家嘲讽了 . 回来自己测试了下 如果通过alloc init生成...

  • 单例正确的写法

  • Singleton正确写法(ARC环境下)

    Singleton 单例的正确写法(ARC环境下) TestSingleton.h TestSingleton.m...

  • iOS-单例的几种写法

    一、静态指针方式(单线程模式单例) 二、多线程加锁单例 三、单例的健壮性 由于水平有限,难免出现纰漏,如有问题还请...

  • OC和Swift单例的写法

    一 、OC中单例的写法:1.普通单例的写法 2. 利用多线程来写单例 #pragma mark --- 普通单例写...

  • Swift单例的正确写法

    虽然入坑时曾经用Swift2.0写过4个多月代码,后来换公司项目又用OC了,现在打算用Swift写代码了. OC...

网友评论

      本文标题:iOS-单例的正确写法

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