单例模式-如何保证单例对象全局唯一性?

单例概念:整个应用或系统只能有该类的一个实例,即是在整个项目中,这个类的对象只能被初始化一次。单例类保证了应用程序的生命周期中有且仅有一个该类的实例对象,而且易于外界访问。

“单例模式中,怎么保证这个单例对象是唯一的。或者说如果在一个对外开放的SDK中,怎么才能保证用户获得的对象是唯一的单例?”

当被问到这个问题的时候,其实是有点懵的。单例模式的单例对象不就是唯一的吗?否则怎么称之为单例模式?带着疑问,写出了常用的单例模式。


static UserDataManager *_shareManager;

+ (instancetype)shareManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _shareManager = [[UserDataManager alloc] init];
    });
    return _shareManager;
}

心想,都已经这个样子了,怎么会不唯一呢?那么问题出现在哪里?很容易发现通过类方法shareManager获取的单例对象是唯一的。但是只有这一种方法才能获取单例类的实例化对象吗?

并不是!

比如说,通过alloc初始化的对象。它是单例类的对象,但它并不是单例对象。所以就出现了不唯一的状况,尤其是在使用者不知情的情况下,难免会出现问题

再比如,如果实现了NSCopying协议,通过copy方法得到单例对象的复制体,也会产生不唯一的单例类的对象。

所以,上面那种写法并没有错,只是忽视了一个很重要的问题:保证单例对象的唯一性,限制其它状况的产生。

解决方法一:默默付出,将初始化与拷贝的对象指向单例对象

static UserDataManager *_shareManager;

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

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

- (id)copyWithZone:(NSZone *)zone {
    return [UserDataManager shareManager];
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return [UserDataManager shareManager];
}

测试结果:

UserDataManager *manager = [[UserDataManager alloc] init];
manager.userName = @"Json";
[UserDataManager shareManager].userName = @"李四";
NSLog(@"%@",manager);
NSLog(@"%@",[UserDataManager shareManager]);
UserDataManager *managerCopy = [[UserDataManager shareManager] copy];
NSLog(@"%@",managerCopy);
    
// <UserDataManager: 0x60000374c5f0> 
// <UserDataManager: 0x60000374c5f0>
// <UserDataManager: 0x60000374c5f0>

这种情况下通过alloccopy的方式获取的依旧是唯一的单例对象。

解决方法二:强势限制,alloccopy方法中抛异常

如果没有实现NSCopying协议与copyWithZone:方法,调用copy会报错。所以这里可以只对alloc方法中设置异常提示。

+ (instancetype)alloc {
    if (_shareManager) {
        NSException *exception = [NSException exceptionWithName:@"重复创建单例对象" reason:@"未使用单例方法" userInfo:nil];
        [exception raise];
    }
    return [super alloc];
}

当程序被迫中止,就知道有些对象是单例对象,并不是随随便就能用的。

单例对象从初始化开始,在程序的整个证明周期内存在。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值