iOS之手写单例

一 不严谨写法

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

  • SignalModel.h
@interface SignalModel : NSObject
+ (instancetype)shareInstance;
@end
  • SignalModel.m
@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方法返回单例对象

二 正确写法
  • SignalModel.m
// 实现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

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

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 13,887评论 1 32
  • 单例模式 什么是单例模式? 单例模式想一个大独裁者,他规定在他的国度里面,所有数据的访问和请求都得经过他,甚至你要...
    GitHubPorter阅读 4,906评论 0 4
  • 单例一般作为:工具类 单例命名:一般情况下如果一个类是单例,那么就要提供一个类方法用于快速创建单例对象,而且这个类...
    甘哲157阅读 5,721评论 0 15
  • 科创板优势 1、转板新兴战略IPO诱惑,新兴板是证监会五大重点工作任务之一,适合规模稍大、越过成长期、相对成熟的企...
    雅蜜蜜阅读 1,526评论 0 0
  • 今日总结:上午还是工作效率比较低,今天该维护的资源还差一点,4月22号到28号的没有维护到,明天补上。 ...
    迷失第二季阅读 1,594评论 0 1

友情链接更多精彩内容