iOS OC创建一个完整的单例(Singleton)

iOS OC创建一个完整的单例(Singleton)_第1张图片
我放的风筝-鲨鱼摆摆

昨天总结了swift的单例创建模式,今天总结一下OC单例的创建模式

单例用处:主要用在封装网络请求,播放器,存放常用数据。
单例特点:只初始化一次,生命和程序的生命周期相同,访问方便。

创建单例最初的学习到的写法是判断对象是否为空,为空才创建,但这仅仅是单线程安全,为了多线程安全,创建单例时会加锁,写法如下

+ (instancetype)shareManager{
    @synchronized(self){
        if (!manager) {
            manager = [[self alloc]init];
        }
        return manager;
    }
}

后来发现GCD创建单例更加简便

static DataManager *manager = nil;

@implementation DataManager

+ (instancetype)shareManager{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc] init];
    });
    return manager;
}
@end

此时单例就已经写好了,只要我们在外面调用shareManager这个方法,返回的对象始终是一个,因为dispatch_once只执行一次。

1、如果不小心调用了alloc、allocWithZone方法呢?此时的manager还是同一个对象吗?

答案:当然不是。

解决方法:参考从 Objective-C 里的 Alloc 和 AllocWithZone 谈起这篇文章加上事件证明,发现调用alloc方法时,会自动调用allocWithZone方法,此时只需要重写AllocWithZone即可。

+ (id)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [super allocWithZone:zone];
    });
    return manager;
}

此时的DataManager.m代码如下

#import "DataManager.h"

@interface DataManager()
@end

static DataManager *manager = nil;
@implementation DataManager

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

+ (id)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [super allocWithZone:zone];
    });
    return manager;
}
@end

2、如果不小心调用了copy、mutableCopy方法呢?此时还是同一个对象吗?

答案:运行崩溃。

崩溃原因:提示[DataManager copyWithZone:]: unrecognized selector sent to instance 0x600003b71710',因为对应自己定义的类,要实现copy就要默认实现NSCopying协议,同理实现mutablecopy就要实现NSMutableCopying协议。

解决办法:那就实现NSCopying的方法- (id)copyWithZone:(nullable NSZone *)zone;和NSMutableCopying的方法- (id)mutableCopyWithZone:(nullable NSZone *)zone;因为要保持manager始终是一个单例,此时直接返回已经初始化的对象。

此时的DataManager.m代码如下

#import "DataManager.h"

@interface DataManager()

@end

static DataManager *manager = nil;

@implementation DataManager

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

+ (id)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [super allocWithZone:zone];
    });
    return manager;
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
    return manager;
}

- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
    return manager;
}
@end


到此一个完整的单例创建就完成啦~~~

当然也有别的方法实现,就是在shareManager方法里面,不添加dispatch_once,这样子每调用一次[DataManager shareManager]就会执行一次init,那此时init方法需要使用dispatch_once,避免多次进行初始化,代码如下:

#import "DataManager.h"

@interface DataManager()

@end

static DataManager *manager = nil;

@implementation DataManager

+ (instancetype)shareManager{
    return [[self alloc] init];
}

- (instancetype)init{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [super init];
    });
    return manager;
}
+ (id)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [super allocWithZone:zone];
    });
    return manager;
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
    return manager;
}

- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
    return manager;
}

最后,我还是推崇第一种方式,调用shareManager方法时,看到使用了dispatch_once,就知道这是个单例啦,很多大牛的三方,都是用的第一种方式勒~

参考地址:
iOS-单例模式写一次就够了
iOS开发多线程篇—单例模式
从 Objective-C 里的 Alloc 和 AllocWithZone 谈起
Objective-C copy,看我就够了

喜欢就点个赞吧✌️✌️
有错之处,还请指出,感谢

你可能感兴趣的:(iOS OC创建一个完整的单例(Singleton))