OC-开发案例收集

iOS之手写单例

2019-03-24  本文已影响191人  路飞_Luck
一 不严谨写法

先附上不严谨的创建单例的写法

@interface SignalModel : NSObject
+ (instancetype)shareInstance;
@end
@implementation SignalModel

+ (instancetype)shareInstance {
    static SignalModel *_instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[SignalModel alloc] init];
    });
    return _instance;
}

外界使用

SignalModel *signal1 = [[SignalModel alloc] init];
SignalModel *signal2 = [SignalModel shareInstance];
SignalModel *signal3 = [SignalModel shareInstance];
NSLog(@"\nsignal1 = %@\nsignal2 = %@\nsignal3 = %@\n",signal1,signal2,signal3);

打印结果

image.png
  1. 通过上面的测试,可以看到通过shareInstance方法获取的对象是相同的,但是用allocinit构造对象时,得到的对象却是不一样的。
  2. 通过不同的方式获得不同的对象,是有问题的,所以要封锁初始化的方式,如alloccopymutableCopynew

摘抄的原理哈

创建对象的步骤分为申请内存(alloc)初始化(init)这两个步骤,我们要确保对象的唯一性,因此在第一步这个阶段我们就要拦截它。当我们调用alloc方法时,OC内部会调用allocWithZone这个方法来申请内存,我们覆写这个方法,然后在这个方法中调用shareInstance方法返回单例对象,这样就可以达到我们的目的。拷贝对象也是同样的原理,覆写copyWithZone方法,然后在这个方法中调用shareInstance方法返回单例对象

二 正确写法
// 实现copy协议
@interface SignalModel()<NSCopying, NSMutableCopying>

@end

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

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

- (id)copyWithZone:(NSZone *)zone {
    return self;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return self;
}
  1. shareInstance单例方法中,变量的初始化改成[[super allocWithZone:NULL] init]
  2. 实现copyWithZone:mutableCopyWithZone:方法

测试代码

SignalModel *signal1 = [[SignalModel alloc] init];
SignalModel *signal2 = [SignalModel shareInstance];
SignalModel *signal3 = [SignalModel shareInstance];
SignalModel *signal4 = [SignalModel new];
SignalModel *signal5 = [signal1 copy];
SignalModel *signal6 = [signal2 mutableCopy];
    
NSLog(@"\nsignal1 = %@\nsignal2 = %@\nsignal3 = %@\nsignal4 = %@\nsignal5 = %@\nsignal6 = %@",signal1,signal2,signal3,signal4,signal5,signal6);

打印结果

image.png

无论通过哪种方式创建出来的实例对象,其内存地址都是一样的,所以该种写法才是严谨的。

上一篇 下一篇

猜你喜欢

热点阅读