1.什么是设计模式?
在计算机编程语言中有23种设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样,在iOS中常用的实际模式为:代理方法,MVC模式,MVVC模式,单例模式等。
什么是单例设计模式?
单例顾名思义就是说一个类的实例只能有一个,在Java、C++这类语言中,可以通过将构造函数私有化来避免对象的重复创建,
但是Objective-C却不能够这样做,我们需要通过其他机制来达到这个目的。
我们知道,创建对象的步骤分为申请内存(alloc)、初始化(init)这两个步骤,我们要确保对象的唯一性,
因此在第一步这个阶段我们就要拦截它。当我们调用alloc方法时,oc内部会调用allocWithZone这个方法来申请内存,我们覆写这个方法,
然后在这个方法中调用shareInstance方法返回单例对象,这样就可以达到我们的目的。
拷贝对象也是同样的原理,覆写copyWithZone方法,然后在这个方法中调用shareInstance方法返回单例对象
代码如下:
#import
@interface Tools : NSObject
// 一般情况下创建一个单例对象都有一个与之对应的类方法
// 一般情况下用于创建单例对象的方法名称都以share开头, 或者以default开头
+ (instancetype)shareInstance;
@end
#import "Tools.h"
@implementation Tools
+ (instancetype)shareInstance
{
Tools *instance = [[self alloc] init];
return instance;
}
// 创建一个空对象
static Tools * _instance = nil;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
// // 当前代码在多线程中可能会出现问题(多线程并发问题.出现多个线程同时创建对象,线程不安全)
// NSLog(@"%s",__func__);
// // 由于所有的创建方法都会调用该方法, 所以只需要在该方法中控制当前对象只创建一次即可
// if (_instance == nil) {
// NSLog(@"创建了一个对象");
// _instance = [[super allocWithZone:zone] init];
//
// }
// return _instance;
// 线程安全的单例写法
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[super allocWithZone:zone] init];
});
return _instance;
}
// MRC
- (oneway void)release
{
// 为了保证程序过程中只有一份实例,这个方法什么都不做.
}
- (instancetype)retain
{
return _instance;
}
- (NSUInteger)retainCount
{
// return 1;
// 注意: 为了方便程序员之间沟通,一般情况下不会再单例中返回retainCount = 1;
// 而是返回一个比较大的值
return MAXFLOAT;
}
@end
效果如下:
main:
#import
#import "Tools.h"
int main(int argc, const char * argv[]) {
// 单例就是无论怎么创建都只能有一个实例对象
// 如果地址相同就代表着是同一个实例对象
Tools *t1 = [[Tools alloc] init]; //内部会调用 allocWithZone
Tools *t2 = [Tools new]; // [[alloc] init] allocWithZone
Tools *t3 = [Tools shareInstance];
NSLog(@"t1 = %p",t1);
NSLog(@"t2 = %p",t2);
NSLog(@"t3 = %p",t3);
// Tools *t2 = [[Tools alloc] init];
// [t2 retain];
// [t2 retain];
// [t2 retain];
// [t2 retain];
// NSLog(@"retainCount = %lu",[t2 retainCount]);
// NSLog(@"t2 = %p",t2);
// [t2 release];
//
// Tools *t1 = [Tools shareInstance];
// NSLog(@"t1 = %p",t1);
// [t1 release];
return 0;
}
输出结果:
ARC输出结果:
2017-07-30 23:09:29.707705+0800 单例ARC写法和MRC写法[5474:213457] t1 = 0x100202690
2017-07-30 23:09:29.707915+0800 单例ARC写法和MRC写法[5474:213457] t2 = 0x100202690
2017-07-30 23:09:29.707931+0800 单例ARC写法和MRC写法[5474:213457] t3 = 0x100202690
MRC输出结果:(上方main方法中,注释的代码打开)
2017-07-30 23:10:11.185137+0800 单例ARC写法和MRC写法[5498:213824] retainCount = 4298126752
2017-07-30 23:10:11.185336+0800 单例ARC写法和MRC写法[5498:213824] t2 = 0x1003035a0
2017-07-30 23:10:11.185364+0800 单例ARC写法和MRC写法[5498:213824] t1 = 0x1003035a0
注意:这里我解释一下.在Tools的.m方法中.如果是ARC的情况.不必要重写release,retain,retainCount方法.
如果是MRC,要想实现单例,必须重写这个三个方法.
从输出结果上来,对象的地址都是一样的,说明是同一块存储空间.这样就只创建了一个对象.