欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

单例全局唯一性

程序员文章站 2022-07-14 08:06:34
...

如何实现单例全局唯一


很多人看到标题可能会不屑一顾,单例本身就是全局唯一的啊,这也是我这几年一直坚信的从未怀疑的事实????

static Manager *manager = nil;

+ (instancetype)managerCenter {
    
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        manager = [[Manager alloc] init];
    });
    
    return manager;
}

相信大部分人都是这一种写法,简单直观又明了。但是假设一个在多人合作的项目里,同事B在不知Manager是单例的情况下调用了[Manager alloc]init; 验证一下就会发现这是一个新的对象,我写了**年的居然到最近才发现这个事实????。

那么如何保证无论使用者如何调用都保证单例的全局唯一

方法1:
使用NSAssert重现alloc方法如

+ (instancetype)alloc
{
    NSAssert(NO, @"请使用shared方法");
    return nil;
}

这种方法可以有效的提醒其他的程序员这是一个单例,但是只有等到运行时才能提示。

方法2:

static Manager *defaultManager = nil;
+ (Manager *)defaultManager
{
    @synchronized(self) //保证线程安全
    {
        if (defaultManager == nil)
        {
            defaultManager = [[self alloc] init];
        }
    }
    return defaultManager;
}

+ (id)allocWithZone:(NSZone *)zone
{
    @synchronized(self)
    {
        if (defaultManager == nil)
        {
            return [super allocWithZone:zone];
        }
    }
    return defaultManager;
}

- (id)init
{
    Class class = [self class];
    @synchronized(class)
    {
        if (defaultManager == nil)
        {
            if (self = [super init])
            {
                defaultManager = self; //使Manager赋值初始化
            }
        }
    }
    return  defaultManager;
}

运行如下测试代码,可以发现打印的结果都是一致的。

Manager *m1 = [Manager defaultManager];
NSLog(@"m1 : %p", m1);
Manager *m2 = [[Manager alloc]init];
NSLog(@"m2 : %p", m2);
Manager *m3 = [Manager alloc];
NSLog(@"m3 : %p", m3);
Manager *m4 = [Manager new];
NSLog(@"m4 : %p", m4);

关于@synchronized使用了线程锁详情参见这里 还有这里
这是我iOS遇坑填坑系列中的一篇,如果有大神发现其中的错误请指正,谢谢!