美文网首页设计模式
单例模式(二)

单例模式(二)

作者: ef463f819996 | 来源:发表于2016-05-02 18:00 被阅读40次

    1、在上一篇单例模式(一)中介绍过如何创建单例,那么接下来如何简化一下单例模式。之前的单例模式是这样的:

    SpiderMan.h

    
    #import@interface SpiderMan : NSObject
    
    + (instancetype)shanreSpiderMan;
    
    @end
    
    

    SpiderMan.m

    
    #import "SpiderMan.h"
    
    @implementation SpiderMan
    
    static id _instance;
    
    + (id)allocWithZone:(struct _NSZone *)zone
    
    {
    
    if (_instance == nil) { // 防止频繁加锁
    
    @synchronized(self) {
    
    if (_instance == nil) { // 防止创建多次
    
    _instance = [super allocWithZone:zone];
    
    }
    
    }
    
    }
    
    return _instance;
    
    }
    
    + (id)shanreSpiderMan
    
    {
    
    if (_instance == nil) { // 防止频繁加锁
    
    @synchronized(self) {
    
    if (_instance == nil) { // 防止创建多次
    
    _instance = [[self alloc] init];
    
    }
    
    }
    
    }
    
    return _instance;
    
    }
    
    - (id)copyWithZone:(NSZone *)zone
    
    {
    
    return _instance;
    
    }
    
    @end
    
    

    可以发现,要经常写这一东西:

    
    if (_instance == nil) { // 防止频繁加锁
    
    @synchronized(self) {
    
    if (_instance == nil) { // 防止创建多次
    
    _instance = [[self alloc] init];
    
    }
    
    }
    
    }
    
    

    这些代码其实可以用另外一种方式来实现,GCD中有一个方法是只执行一次的,即:

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{ });

    使用该方法来代替以上代码可以简化许多:

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

    详细代码也可以看github上的例子里的People类。

    2、以上的单例都是在ARC环境下的,在非ARC环境下需要再做处理:

    
    - (oneway void)release { }
    
    - (id)retain { return self; }
    
    - (NSUInteger)retainCount { return 1;}
    
    - (id)autorelease { return self;}
    
    
    • (oneway void)release {} :为了防止对象被释放;

    • (id) retain {return self }: 为了防止产生新的对象;

    • (NSUInteger)retainCount {return 1;} :保证一个对象引用计数始终为1;

    3、如果一个项目当中有非常多的单例类,对每个单例类都进行

    
    + (id)allocWithZone:(struct _NSZone *)zone
    
    {
    
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
    
    _instance = [super allocWithZone:zone];
    
    });
    
    return _instance;
    
    }
    
    + (id)sharePeoper
    
    {
    
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
    
    _instance = [[self alloc]init];
    
    });
    
    return _instance;
    
    }
    
    - (id)copyWithZone:(NSZone *)zone
    
    {
    
    return _instance;
    
    }
    
    

    这样子会非常繁琐,其实可以做相应地简化,简化的方法是:创建一个头文件,宏定义单例头文件和.m文件。如:

    
    // .h文件
    
    #define HMSingletonH + (instancetype)sharedInstance;
    
    // .m文件
    
    #define HMSingletonM \
    
    static id _instance; \
    
    \
    
    + (id)allocWithZone:(struct _NSZone *)zone \
    
    { \
    
    static dispatch_once_t onceToken; \
    
    dispatch_once(&onceToken, ^{ \
    
    _instance = [super allocWithZone:zone]; \
    
    }); \
    
    return _instance; \
    
    } \
    
    \
    
    + (instancetype)sharedInstance \
    
    { \
    
    static dispatch_once_t onceToken; \
    
    dispatch_once(&onceToken, ^{ \
    
    _instance = [[self alloc] init]; \
    
    }); \
    
    return _instance; \
    
    } \
    
    \
    
    - (id)copyWithZone:(NSZone *)zone \
    
    { \
    
    return _instance; \
    
    }
    
    

    4、那么接下来需要解决的一个问题就是在ARC环境和MRC环境下如何使用宏定义来适配单例模式。方法还是比较简单的,因为可以使用

    
    #if __has_feature(objc_arc) // arc环境
    
    #else  // mrc 环境
    
    #endif
    
    

    来判断是在ARC还是在MRC环境下。不多说,直接上代码(在新建的一个头文件里):

    
    // .h文件
    
    #define HMSingletonH(name) + (instancetype)shared##name;
    
    // .m文件
    
    #if __has_feature(objc_arc)
    
    #define HMSingletonM(name) \
    
    static id _instace; \
    
    \
    
    + (id)allocWithZone:(struct _NSZone *)zone \
    
    { \
    
    static dispatch_once_t onceToken; \
    
    dispatch_once(&onceToken, ^{ \
    
    _instace = [super allocWithZone:zone]; \
    
    }); \
    
    return _instace; \
    
    } \
    
    \
    
    + (instancetype)shared##name \
    
    { \
    
    static dispatch_once_t onceToken; \
    
    dispatch_once(&onceToken, ^{ \
    
    _instace = [[self alloc] init]; \
    
    }); \
    
    return _instace; \
    
    } \
    
    \
    
    - (id)copyWithZone:(NSZone *)zone \
    
    { \
    
    return _instace; \
    
    }
    
    #else
    
    #define HMSingletonM(name) \
    
    static id _instace; \
    
    \
    
    + (id)allocWithZone:(struct _NSZone *)zone \
    
    { \
    
    static dispatch_once_t onceToken; \
    
    dispatch_once(&onceToken, ^{ \
    
    _instace = [super allocWithZone:zone]; \
    
    }); \
    
    return _instace; \
    
    } \
    
    \
    
    + (instancetype)shared##name \
    
    { \
    
    static dispatch_once_t onceToken; \
    
    dispatch_once(&onceToken, ^{ \
    
    _instace = [[self alloc] init]; \
    
    }); \
    
    return _instace; \
    
    } \
    
    \
    
    - (id)copyWithZone:(NSZone *)zone \
    
    { \
    
    return _instace; \
    
    } \
    
    \
    
    - (oneway void)release { } \
    
    - (id)retain { return self; } \
    
    - (NSUInteger)retainCount { return 1;} \
    
    - (id)autorelease { return self;}
    
    #endif
    
    

    以后每次要使用到单例的时候,就导入该头文件,写上两句代码就OK了,例如Person单例:

    .h

    
    #import@interface Person : NSObject
    
    ANSingletonH(Person)
    
    @end
    
    

    .m

    
    #import "Person.h"
    
    @implementation Person
    
    ANSingletonM(Person)
    
    @end
    
    

    也可以到我的github上查看完整代码

    相关文章

      网友评论

        本文标题:单例模式(二)

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