iOS之手写单例

作者: 路飞_Luck | 来源:发表于2019-03-24 22:12 被阅读191次
    一 不严谨写法

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

    • 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

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

    相关文章

      网友评论

        本文标题:iOS之手写单例

        本文链接:https://www.haomeiwen.com/subject/thbpvqtx.html