您的位置:首页 > 其它

创建"全世界最简单"の单例

2016-06-26 20:29 197 查看

知识点

1、什么是单例

2、单例的好处

3、单例创建方式

4、封装”单例的创建”

5、使用单例的封装实现单例

6、使用单例

1、What’s 单例 ?

顾名思义,单例就是一个类只有一个实例对象。确保在程序过程中,无论创建多少次对象,该对象都是同一个实例,都指向同一块存储空空间。在设计模式中单例模式也是很常用的模式。

单例模式的三个要点

该类只能有一个实例;

它必须自行创建这个实例;

必须向外界提供这个实例供调用者调访问。

2、Benefit of 单例

可以保证在程序运行过程中,一个类只有一个实例,而且该实例易于供外界访问

方便的控制了实例个数,并且大大节约系统资源

单例模式的使用场合:在整个应用程序中,共享一份资源(这份资源只需要创建初始化一次)

3、The ways to create 单例

创建方式

a) 利用手动添加线程锁
@synchronized
控制


首先要在类中申明一个私有的静态实例,保证该类被循环引用,这样单例才会一直存在不会被释放。

static id _instance;


要想实例单例,就必须控制类的构造方法,因此重写
allocWithZone
方法。

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
@synchronized (self) {
if(!_instance) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
}


同理,要达到实现单例,按照苹果提供的
[UIApplication sharedApplication]
方式获取单例,需要提供一个sharedInstance的类方法去访问单例。因此需要在类的.h文件中声明工厂方法,并在.m文件中实现。

+ (instancetype)sharedInstance;


+ (instancetype)sharedCar {
@synchronized (self) {
if(!_instance) {
_instance = [[self alloc] init];
}
}
return _instance;
}


当然,有时候我们会用到一个实现了
NSCopying
copy
对象方法,在单例中应该重写该方法,使得赋值的实例仍然是唯一的实例。

- (id)copyWithZone:(NSZone *)zone {
return _instance;
}


b) 通过利用
GCD
中的
dispatch_once
方法控制实例个数


和用线程同步锁一样的道理,要想达到单例的效果,必须控制外界创建实例的方法,而GCD的方式也不例外,只是在控制的方式上利用用
dispatch_once
程序运行过程中只会执行一次
的特性实现,并且
dispatch_once
方法是线程安全的。

static id _instance;

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

+ (instancetype)shared##name {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}

- (id)copyWithZone:(NSZone *)zone {
return _instance;
}


4、封装”单例的创建”

从上面的代码我们可以看出,要想实现一个单例是很容易的。同时也可以看出实现单例的代码都是差不多一样的,除了可能在类的工厂方法的名字可能采用
instance***
以为,其余的代码都是一模一样,而这样的代码重复工作量,在我们进行开发的过程中是没有多大意思并且花费时间,因此可以借用宏的特性将单例的实现进行封装,只要每次在.h文件中引入宏,并且调用宏的方法就可以实现单例。那么我不啰嗦了,直接上代码。

1. 首先需要创建一个.h文件
MRSingleton.h
(当然该文件名可以根据个人喜好取名),在.h文件中进行宏的定义。

// .h 文件中需要声明的方法宏定义
#define MRSingletonH(name) + (instancetype)shared##name;

// .m 文件中需要的方法宏定义
#define MRSingletonM(name) \
static id _instance;\
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone {\
\
static dispatch_once_t onceToken;\
\
dispatch_once(&onceToken, ^{\
\
_instance = [super allocWithZone:zone];\
\
});\
\
return _instance;\
}\
\
+ (instancetype)shared##name {\
\
static dispatch_once_t onceToken;\
\
dispatch_once(&onceToken, ^{\
\
_instance = [[self alloc] init];\
\
});\
\
return _instance;\
}\
\
- (id)copyWithZone:(NSZone *)zone {\
\
return _instance;\
}


注意!!!

需要特别注意的是上面的宏定义中的
\
是一定不能获缺的,因为编译器在检测宏时默认只会认为define所在一行才是宏的定义内容,因此只会将所在行的代码进行宏的替换,
\
的的作用就是告诉编译器后面一行的内容仍然是宏需要替换的代码。

5、使用单例的封装实现单例

1 在声明文件.h文件中导入宏定义文件
MRSingleton.h


#impport "MRSingleton.h"


2 在.h文件中调用宏的方法
MRSingletonH(类名)
(在MRSingletonH后括号中填入类名, 生成方法
instanceMRPerson
的方法声明)

@interface MRPerson : NSObject

// 调用宏声明单例方法
MRSingletonH(Person)

@end


3 在.h 文件中调用宏的方法
MRSingletonH(类名)


@interface MRPerson ()<NSCopying>
@end

@implementation MRPerson

// 调用宏实现单例方法
MRSingletonM(MRPerson)

@end


6、单例使用

#pragma mark --- 利用GCD实现单例
// 原始方法创建
MRPerson *person2 = [[MRPerson alloc] init];
// 单例方法创建
MRPerson *person1 = [MRPerson sharedPerson];
// copy
MRPerson *person3 = [person2 copy];

NSLog(@"[MRPerson sharedPerson]---%@", person1);
NSLog(@"[[MRPerson alloc] init]---%@", person2);
NSLog(@"[person2 copy]---%@", person3);

ViewController *viewController1 = [ViewController sharedViewController];
ViewController *viewController2 = [[ViewController alloc] init];
ViewController *viewController3 = [viewController2 copy];

NSLog(@"[ViewController sharedViewController]---%@", viewController1);
NSLog(@"[[ViewController alloc] init]---%@", viewController2);
NSLog(@"[viewController2 copy]---%@", viewController3);


2016-06-26 20:26:10.903 单例模式-OC[3818:214382] [MRPerson sharedPerson]---<MRPerson: 0x7bf2cdb0>
2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [[MRPerson alloc] init]---<MRPerson: 0x7bf2cdb0>
2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [person2 copy]---<MRPerson: 0x7bf2cdb0>
2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [ViewController sharedViewController]---<ViewController: 0x7bf29c40>
2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [[ViewController alloc] init]---<ViewController: 0x7bf29c40>
2016-06-26 20:26:10.904 单例模式-OC[3818:214382] [viewController2 copy]---<ViewController: 0x7bf29c40>


可以看出单例已经成功创建,每一个实例对象都指向同一块内存空间!!!(ps:这篇是OC版,后续会用swift实现)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  单例