单例模式
有时候我们需要一个全局的对象,而且要保证全局有且仅有一份即可,这时候就需要用到单例设计模式,但是需要注意的是:在多线程的环境下也需要做好线程保护。其实系统已经有很多单例存在,例如UIApplication、NSNotification、NSFileManager、NSUserDefaults等.以下代码详解
ARC环境下严谨的单例模式
#import
@interface JHTool : NSObject
//类方法
//1.方便访问
//2.标明身份
//3.注意:share+类名|default + 类名 | share | default | 类名
+(instancetype)shareTool;
@end
#import "JHTool.h"
@implementation JHTool
//提供一个全局静态变量
static JHTool * _instance;
+(instancetype)shareTool{
return [[self alloc]init];
}
//当调用alloc的时候会调用allocWithZone
+(instancetype)allocWithZone:(struct _NSZone *)zone{
//方案一:加互斥锁,解决多线程访问安全问题
// @synchronized(self){//同步的
// if (!_instance) {
// _instance = [super allocWithZone:zone];
// }
// }
//方案二.GCD dispatch_onec,本身是线程安全的,保证整个程序中只会执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
//严谨
//遵从NSCopying协议,可以通过copy方式创建对象
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
return _instance;
}
//遵从NSMutableCopying协议,可以通过mutableCopy方式创建对象
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
return _instance;
}
@end
#import "ViewController.h"
#import "JHTool.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
JHTool * tool1 = [[JHTool alloc]init];
JHTool * tool2 = [JHTool shareTool];
JHTool * tool3 = tool1.copy;
JHTool * tool4 = tool2.mutableCopy;
NSLog(@"tool1:%p,tool2:%p,tool3:%p,tool4:%p,",tool1,tool2,tool3,tool4);
printf("tool1:%p,tool2:%p,tool3:%p,tool4:%p,",tool1,tool2,tool3,tool4);
}
@end
打印结果:
MRC环境下严谨的单例模式
Xcode5以后项目默认都是ARC,所以把项目设置成MRC环境,选择项目 Target -> Build Sttings -> All -> 搜索‘Automatic’ -> 把 Objective-C Automatic Reference Counting 设置为 NO ,如下图:
MRC单例模式代码详解
#import
@interface HJTool : NSObject
//类方法
+(instancetype)shareTool;
@end
#import "HJTool.h"
@implementation HJTool
//修改环境为MRC:选择项目 Target -> Build Sttings -> All -> 搜索‘Automatic’ -> 把 Objective-C Automatic Reference Counting 设置为 NO
//提供一个静态全局变量
static HJTool * _instance;
//实现类方法
+(instancetype)shareTool{
return [[self alloc]init];
}
//alloc会调用allocWithZone
+(instancetype)allocWithZone:(struct _NSZone *)zone{
//方法一.互斥锁保证线程安全
// @synchronized(self){
// if (_instance == nil) {
// _instance = [super allocWithZone:zone];
// }
// }
//方法一.GCD-> dispatch_once_t 该方法只会执行一次,本身线程安全
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
-(id)copyWithZone:(NSZone *)zone{
return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
return _instance;
}
//MRC特有的
-(instancetype)retain{
return _instance;
}
-(oneway void)release{
NSLog(@"%zd",_instance.retainCount);
}
#import "ViewController.h"
#import "HJTool.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor yellowColor];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
HJTool * t1 = [[HJTool alloc]init];
HJTool * t2 = [[HJTool alloc]init];
HJTool * t3 = [HJTool shareTool];
HJTool * t4 = [t1 copy];
HJTool * t5 = [t2 mutableCopy];
HJTool * t6 = [t1 retain];
NSLog(@"t6.retainCount : %zd",t1.retainCount);
NSLog(@"t1:%p t2:%p t3:%p t4:%p t5:%p t6:%p",t1,t2,t3,t4,t5,t6);
}
打印结果
拓展:区分是MRC还是ARC的宏
#if __has_feature(objc_arc)
//条件满足 ARC,可以处理ARC的代码
NSLog(@"ARC");
#else
//条件满足 MRC,,可以处理MRC的代码
NSLog(@"MRC");
#endif
通用的单例模式
在
SingleDog.h
文件中定义一个宏,SingleH(name)
定义单例.h文件的类方法声明,SingleM(name)
定义和实现单例.m文件的方法,定义的宏的代码如下
#define SingleH(name) +(instancetype)share##name;//.h文件替换
//.m文件替换
#if __has_feature(objc_arc)//arc
//条件满足 ARC
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
\
return _instance;\
}\
\
+(instancetype)share##name\
{\
return [[self alloc]init];\
}\
\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}
#else
//条件满足 MRC
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
\
return _instance;\
}\
\
+(instancetype)share##name\
{\
return [[self alloc]init];\
}\
\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
-(oneway void)release\
{\
}\
\
-(instancetype)retain\
{\
return _instance;\
}
#endif
单例
SingleTool
文件,头文件和实现文件分别调用宏的SingleH(name)
,SingleM(name)
即可,代码如下
#import
#import "SingleDog.h"
@interface SingleTool : NSObject
//替换头文件
SingleH(SingleTool)
@end
#import "SingleTool.h"
@implementation SingleTool
SingleM(SingleTool)
@end
#import "ViewController.h"
#import "SingleTool.h"
@interface ViewController ()
@end
@implementation ViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
SingleTool * t1 = [[SingleTool alloc]init];
SingleTool * t2 = [SingleTool shareSingleTool];
SingleTool * t3 = [t1 copy];
SingleTool * t4 = [t1 mutableCopy];
#if __has_feature(objc_arc)
//条件满足 ARC,可以处理ARC的代码
NSLog(@"ARC");
#else
//条件满足 MRC,,可以处理MRC的代码
NSLog(@"MRC");
SingleTool * t5 = [t1 retain];
NSLog(@"t6.retainCount : %zd",t1.retainCount);
NSLog(@"t1:%p t2:%p t3:%p t4:%p t5:%p",t1,t2,t3,t4,t5);
#endif
}
@end
MRC环境下打印结果如下: