单例模式的作用:可以保证在程序运行过程中,一个类只有一个实例,而且该实例易于外界访问(说白了就是节省一些内存),其实面试的时候也就是让你手动写下单例,基本固定用GCD,没什么技术含量,平时放在一个类里面或者快捷方式里面就好了
.h文件
#import <Foundation/Foundation.h>
@interface SLDemo : NSObject<NSCopying>
+ (instancetype)sharedInstance;
@end
.m文件
id _testStr = @"testStr";
static id _instance; //static修饰一个全局变量,表示该变量只能本文件内部访问,外部无法访问 修改,用来保存唯一的单例对象
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone]; //申请内存
});
// if (_instance == nil) { //防止频繁加锁
// @synchronized(self) {
// if (_instance == nil) { //防止多次创建
// _instance = [super allocWithZone:zone];
// }
// }
// }
return _instance;
}
+ (instancetype)sharedInstance {
NSLog(@"%@",_testStr);
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init]; //调用allocWithZone
});
// if (_instance == nil) { //防止频繁加锁
// //防止多线程一起进来,加锁
// @synchronized(self) {
// if (_instance == nil) { //防止多次创建
// _instance = [[self alloc] init];
// }
// }
// }
return _instance;
}
- (id)copyWithZone:(NSZone *)zone {
return _instance;
}
@end
调用
- (void)viewDidLoad {
[super viewDidLoad];
[self createSLDemo];
}
- (void)createSLDemo {
//extern关键字是告诉编译器整个工程搜索id _testStr的全局变量,我们就可以更改搜索到后
extern id _testStr;
_testStr = @"string";
SLDemo * SL1 = [SLDemo sharedInstance];
SLDemo * SL2 = [SLDemo sharedInstance];
SLDemo * SL3 = [SLDemo sharedInstance];
SLDemo * SL4 = [SLDemo sharedInstance];
NSLog(@"%@ %@ %@ %@",SL1, SL2, SL3, SL4);
}
@en
会发现打印出的地址是一样的四个,证明只调用了一次,创建了一个共同的实例
解释:上面.m文件用的是static修饰,假如去掉static,就像extern一样,拿出来可以改变,这样单例就很危险了,很可能会被其他人修改,那这样就不叫单例了
上面的单例还可以写在一个文件里,用宏调用,比如:
//.h文件宏
#define SLDemoH(name) + (instancetype)shared##name;
//.m文件宏
#define SLDemoM \
id _testStr = @"testStr"; \
static id _instance; \
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone \
{\
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \//申请内存
}); \
// if (_instance == nil) { //防止频繁加锁
// @synchronized(self) {
// if (_instance == nil) { //防止多次创建
// _instance = [super allocWithZone:zone];
// }
// }
// }
return _instance;
}
+ (instancetype)shared##name {
NSLog(@"%@",_testStr);
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init]; //调用allocWithZone
});
// if (_instance == nil) { //防止频繁加锁
// //防止多线程一起进来,加锁
// @synchronized(self) {
// if (_instance == nil) { //防止多次创建
// _instance = [[self alloc] init];
// }
// }
// }
return _instance;
}
- (id)copyWithZone:(NSZone *)zone {
return _instance;
}
再就是可以用条件编译区分ARC 和 MRC