• iOS开发之单例设计模式


    本文将从四个方面对iOS开发中的单例设计模式进行讲解:

    一、什么是单例设计模式

    二、我们为什么要用单例设计模式

    三、单例设计模式的基本用法

    四、自定义单例设计模式代码的封装 


    一、什么是单例设计模式

      所谓单例,即是单个的实例化对象,保证一个类有且仅有一个实例。通常情况下,当我们对一个类实例化时(如:alloc、new等)并不能保证每次实例化的对象是唯一的实例。那么为了保证该类可在多次实例化的过程中保证内存地址不变,就需要引入单例设计模式。


    二、我们为什么要用单例设计模式

    1、Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例,如手机中有多个音乐播放器,但需要为用户播放最后打开的播放器中的音乐,为提高用户体验,这种播放工具类就需要用单例来实现。

    2、可提高线程安全,在实例化单例时我们用到了一个dispatch_once函数

    void dispatch_once(
    
        dispatch_once_t *predicate,
    
        dispatch_block_t block);

    该函数在整个程序的声明周期中,仅执行一次某一个block对象,系统已经帮我们加了锁,所以在多个线程抢夺同一资源的时候,他也是安全的


    三、单例设计模式的基本用法

    通常情况下,一般的单例设计模式只需要重写两个方法即可,当然需要用来实例化对象的share或standard的类方法是必要的。

    + (id)allocWithZone:(NSZone *)zone;
    // IOS9.0之后不需要引入NSCopying对copyWithZone方法重写也不会报错
    - (id)copyWithZone:(NSZone *)zone;

    实现单例的类方法:

    static id _instance;
    
    + (instancetype)shareAudioPlayer {
        /**
         一次性执行
         dispatch_once是安全的,系统已经帮我们加了锁,所以在多个线程抢夺同一资源的时候,他也是安全的
         */
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSLog(@"---once---");
            
            _instance = [[self alloc] init];
        });
    
        return _instance;
    }

    对以上两个方法的重写

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

    单例设计模式在ARC与非ARC下的内部机制后有一些不同,下面我们分别就两种内存管理模式对单例设计模式进行说明。

    如果在ARC下,上面的代码便足够实现单例设计模式,以下代码不需重写。

    如果在MRC下,则在重写以上两个方法的基础上,还要对下面的四个方法进行重写:

    - (id)retain;
    
    - (NSUInteger)retainCount;
    
    - (void)release;
    
    - (id)autorelease;
    // MRC下还要重写以下方法
    - (oneway void)release {}
    
    - (instancetype)retain {return _instance;}
    
    - (instancetype)autorelease {return _instance;}
    
    - (NSUInteger)retainCount {return 1;}

    以上即为单例设计模式在ARC或MRC下的用法。如果需要同时兼容MRC或ARC就需要对缩写代码进行判断,我们一般用条件编译来进行判断:

    #if __has_feature(objc_arc) // ARC
        
        NSLog(@"MRC下插入ARC代码也是可以的,在MRC下也不会报错,但不会被执行");
    
    #else  // MRC
    
        NSLog(@"ARC下插入MRC代码也是可以的,在ARC下也不会报错,但不会被执行");
    
    #endif

    四、自定义单例设计模式代码的封装

    在我们工作过程中,如果需要自定义单例设计模式,以上代码难免会重复编写,为了提高工作效率,可考虑将代码进行封装

    singleton_h(DBTool)
    singleton_m(DBTool)
    
    /**
     单例抽取成宏,只需要改两个部分,一个是.h文件里面的内容,一个是.m文件里面的内容
     宏里面拼接参数用两个 ##
     */
    
    // .h文件单独抽取
    #define singleton_h(name) 
    + (instancetype)share##name;
    
    #if __has_feature(objc_arc) // ARC环境下
    
    #define singleton_m(name) 
    static id _instance; 
    
    + (instancetype)share##name { 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
    _instance = [[self alloc] init]; 
    }); 
    return _instance; 
    } 
    
    + (instancetype)allocWithZone:(struct _NSZone *)zone { 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
    _instance = [super allocWithZone:zone]; 
    }); 
    return _instance; 
    } 
    
    - (id)copyWithZone:(NSZone *)zone { 
    return _instance; 
    } 
    
    #else // 非ARC环境下(MRC)
    
    #define singleton_m(name) 
    static id _instance; 
    
    + (instancetype)share##name { 
        static dispatch_once_t onceToken; 
        dispatch_once(&onceToken, ^{ 
            _instance = [[self alloc] init]; 
        }); 
        return _instance; 
    } 
    
    + (instancetype)allocWithZone:(struct _NSZone *)zone { 
        static dispatch_once_t onceToken; 
        dispatch_once(&onceToken, ^{ 
            _instance = [super allocWithZone:zone]; 
        }); 
        return _instance; 
    } 
    
    - (id)copyWithZone:(NSZone *)zone { 
        return _instance; 
    } 
    
    - (oneway void)release {} 
    - (instancetype)retain {return _instance;} 
    - (instancetype)autorelease {return _instance;} 
    - (NSUInteger)retainCount {return 1;}
    
    #endif
    

    如果本文有任何错误之处,欢迎拍砖指正,共同进步, 谢谢!

  • 相关阅读:
    mysql连接数过多 解决方案
    单列模式下的数据库连接与Servlet之间页面访问用户登录的小例子
    Spring MVC理解和主要使用的注解详解
    Spring JDBC 框架中, 绑定 SQL 参数的另一种选择:具名参数(named parameter)
    xlwings
    openpyxl
    【python】Excel两表中某个信息对比
    pycharm中配置python版本问题
    python指令提示不是内部或外部命令(环境变量配置)
    python管理电脑文件及文件夹
  • 原文地址:https://www.cnblogs.com/Jepson1218/p/5172243.html
Copyright © 2020-2023  润新知