iOS开发之单例

作者: hmj1993 | 来源:发表于2018-05-04 15:36 被阅读144次

    由于iOS开发中经常会用到单例,所以就做个简单的总结。

    单例模式
    • 作用:
      可以保证在程序运行过程中,一个类只有一个实例,而且该实例易于供外界访问,从而方便的控制了实例个数,并节约系统资源
    • 使用场合:
      在整个应用程序中,共享一份资源(这份资源只需要创建初始化一次)

    arc环境下实现单例模式

    #import <Foundation/Foundation.h>
    //重写copy的相关方法时必须引入copy的相关文件
    @interface danli : NSObject<NSCopying,NSMutableCopying>
    
    //类方法
    //1.方便访问
    //2.标明身份
    //3.命名规范 share/default + 类名
    +(instancetype)shareDanli;
    
    @end
    
    #import "danli.h"
    
    @implementation danli
    
    //0.提供全局变量
    static danli *_instance;
    //1.alloc
    +(instancetype)allocWithZone:(struct _NSZone *)zone
    {
        //method 1
        //加互斥锁解决多线程访问安全问题
        @synchronized(self){
           
            if (_instance==nil) {
                _instance=[super allocWithZone:zone];
            }
        }
        
        //method 2
        //本身就是线程安全的,不需要担心多线程安全问题
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance=[super allocWithZone:zone];
        });
        
        return _instance;
    }
    //2.提供类方法
    +(instancetype)shareDanli{
        return [[self alloc]init];
    }
    //3.严谨,因为有的时候不止是alloc或new方法创建
    -(id)copyWithZone:(NSZone *)zone{
        return _instance;
    }
    -(id)mutableCopyWithZone:(NSZone *)zone{
        return _instance;
    }
    @end
    

    以上就是在arc的环境下构建单例的方法,mrc的环境下构建单例的方法差不多,就是多重写几个方法

    mrc环境下实现单例模式

    首先,设置一下mrc的开发环境,如下图所示


    屏幕快照 2018-05-04 下午2.56.09.png

    其次,因为在mrc环境下需要在创建实例后进行release操作,但这显然和单例的目标相违背,所以为了不进行销毁,我们可以重写以下方法,

    -(oneway void)release{
    }
    -(instancetype)retain{
        return _instance;
    }
    -(NSUInteger)retainCount{
        return MAXFLOAT;
    }
    

    这样就已经实现了我们的目标

    但是考虑到如果经常切换mrc和arc的环境,我们就需要经常修改相关方法,所以为了解决这个问题,我们可以使用条件编译来动态的根据开发环境来进行mrc和arc的不同考虑,也就是将mrc的相关代码放在条件编译的else语句中,这样也就不需要经常修改代码了

    //条件编译
    #if __has_feature(objc_arc)
    //arc
    #else
    //mrc
    -(oneway void)release{
    }
    -(instancetype)retain{
        return _instance;
    }
    -(NSUInteger)retainCount{
        return MAXFLOAT;
    }
    #endif
    

    以上已经完成了单例的操作,但是在一个大的项目中,我们肯定不会只有一个单例,而单例的代码其实也都差不多,如果每次都进行复制,在代码的复用问题上又做的不是很好,所以我们可以考虑将单例的代码写成宏,这样就可以方便使用了,其中,这里使用了带参数的宏,参数即为name,也就是我们自己设置的单例名称

    • 定义.h文件的宏
    #define singerH(name) +(instancetype)share##name;
    
    • 定义.m文件的宏,其中也是使用条件编译区分arc和mrc的开发环境
    #if __has_feature(objc_arc)
    //arc
    #define singerM(name) static id *_instance;\
    +(instancetype)allocWithZone:(struct _NSZone *)zone\
    {\
    @synchronized(self){\
    if (_instance==nil) {\
    _instance=[super allocWithZone:zone];\
    }\
    }\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
    _instance=[super allocWithZone:zone];\
    });\
    return _instance;\
    }\
    +(instancetype)share##name{\
    return [[self alloc]init];\
    }\
    -(id)copyWithZone:(NSZone *)zone{\
    return _instance;\
    }\
    -(id)mutableCopyWithZone:(NSZone *)zone{\
    return _instance;\
    }
    #else
    //mrc
    #define singerM(name) static id *_instance;\
    +(instancetype)allocWithZone:(struct _NSZone *)zone\
    {\
    @synchronized(self){\
    if (_instance==nil) {\
    _instance=[super allocWithZone:zone];\
    }\
    }\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
    _instance=[super allocWithZone:zone];\
    });\
    return _instance;\
    }\
    +(instancetype)share##name{\
    return [[self alloc]init];\
    }\
    -(id)copyWithZone:(NSZone *)zone{\
    return _instance;\
    }\
    -(id)mutableCopyWithZone:(NSZone *)zone{\
    return _instance;\
    }\
    -(oneway void)release{\
    }\
    -(instancetype)retain{\
        return _instance;\
    }\
    -(NSUInteger)retainCount{\
        return MAXFLOAT;\
    }\
    #endif
    

    在使用时,只要在自己创建的单例文件中调用相关的参数宏就可以了

    以上,就是iOS开发中单例的相关使用方法

    相关文章

      网友评论

      本文标题:iOS开发之单例

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