单例

前言 : 单例你我他,使用靠大家,其实的写法是不难的,重点就在代码的使用规范上,开发者在遵守规范编码的时候,能避开一些本不该出现的问题,但是每个开发者的思维总是不尽相同,所以在公司规范强制性稍微差点的项目中,个人风格一定会存在于代码中的。

简单的分析下单例创建的方式以及如何避开使用上的陷阱

单线程单例

+ (instancetype)sharedInstance{
    static DOVESingleThreadSingleton *sharedInstance = nil;
    if (!sharedInstance) {
        sharedInstance = [[DOVESingleThreadSingleton alloc]init];
    }
    return sharedInstance;
}
  • 单线程单例只有在单个线程使用的情况下才是安全的,在多个线程同时使用时,每个线程中都创建了一个非共享的实例,不具有安全性,
  • 在多条线程中同时调用[DOVESingleThreadSingleton sharedInstance];方法,在没有加锁时,会产生多个singleton非共享实例,这违背了单例的原则

多线程加锁单例

通常使用@synchronized 或 dispatch_once的方式
@synchronized采用的是递归互斥锁来实现线程安全,而dispatch_once的内部则使用了很多原子操作来替代锁,以及通过信号量来实现线程同步,而且有很多针对处理器优化的地方,甚至在if判断语句上也做了优化(逼格有点高),使得其效率有很大的提升,虽然其源码很短,但里面包含的东西却很多,所以苹果也推荐使用dispatch_once来创建单例

1、使用 @synchronized 加锁
+ (instancetype)sharedInstance {
    static DOVEMultithreadingsingeton *sharedInstance;
    @synchronized (self) {
        if (!sharedInstance) {
            sharedInstance = [[DOVEMultithreadingsingeton alloc] init];
        }
    }
    return sharedInstance;
}
  • 因为使用@synchronized加了锁,所以避免了创建多个非共享实例。但是和dispatch_once加锁相比,性能差点
2、使用dispatch_once加锁

2.1、禁用外部调用除sharedInstance之外的方法

.h
-(instancetype)init NS_UNAVAILABLE;
+(instancetype)new NS_UNAVAILABLE;
-(id)copy NS_UNAVAILABLE;
-(id)mutableCopy NS_UNAVAILABLE;

+ (instancetype)sharedInstance;
.m
+(instancetype)sharedInstance{
    static DOVEMultithreadingsingeton *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc]init];        
    });
    return sharedInstance;
}
  • 为了防止init、new等在不同线程中创建引起的错误,使用NS_UNAVAILABLE禁用相关的创建方法

2.2 、不禁用其他方法,但要做保证安全的处理

+(instancetype)sharedInstance{
    static DOVEMultithreadingsingeton *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[super allocWithZone:NULL] init];
    });
    return sharedInstance;
}

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

-(id)copy{
    return [DOVEMultithreadingsingeton sharedInstance];
}

-(id)mutableCopy{
    return [DOVEMultithreadingsingeton sharedInstance];
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone {
    return [DOVEMultithreadingsingeton sharedInstance];
}
  • 对各种初始创建的方法做安全处理
  • 因为重写了初始化创建的方法,所以不能在使用[[self alloc]init], 该用调用父类的分配空间,如果使用了,那么会与[[allocWithZone:NULL]init]造成死锁

使用单例在整个项目中只会创建一次共享实例,故单例具:有线程安全、代码量少、满足静态分析器的要求等优势,但是对单例类使用init、new等创建时,会导致出现多个类对象的问题,所以应做相关的安全处理,避免其他人调用时因为不规范调用引起问题。
单例一般使用还是蛮简单的,但涉及到一些骚操作的滥用时,还是会导致线程卡死、死锁等crash的,所以规范使用还是很重要的

关于@synchronized 和 dispatch_once的区别请参考
@synchronized 和 dispatch_once的区别

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值