您的位置:首页 > 移动开发 > IOS开发

iOS开发之单例设计模式

2016-01-30 22:20 323 查看
本文将从四个方面对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


如果本文有任何错误之处,欢迎拍砖指正,共同进步, 谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: