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

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

原文地址:https://www.cnblogs.com/Jepson1218/p/5172243.html