释放双眼,带上耳机,听听看~!
单例模式在iOS开发中可能算是最常用的模式之一了.(废话不多说, 直接进入主题)
1. 什么是单例模式?
a.整个程序运行期间, 永远只分配一块内存来创建对象
b.最好提供一个类方法,返回内部唯一的一个对象(一个实例)
2. 该怎样去写?
2.1. 一般情况下, 我们可以这样写:
注意:当我们调用sharedInstance方法获取到的对象的确是相同的,
但是当我们通过alloc和init来构造对象的时候, 得到的对象却不一样. 所以这样写是有缺陷的.
@interface Singleton : NSObject
+ (instancetype)shareInstance ;
@end
@implementation Singleton
static Singleton *_instance = nil;
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
}) ;
return _instance ;
}
小结: 使用上面的这种方法, 导致我们通过不同的途径去创建得到不同的对象, 显然不行, 我们设计单例模式, 就必须要确保对象的唯一性, 所以我们就需要对alloc/init/copy等等方法进行过滤.
创建对象时会进行alloc(申请内存)和init(初始化)俩个步骤,
而调用alloc方法时, OC内部会调用allocWithZone来申请内存, 我们想要确保对象是唯一的, 所以我们得重写这些方法.
而调用alloc方法时, OC内部会调用allocWithZone来申请内存, 我们想要确保对象是唯一的, 所以我们得重写这些方法.
ARC中: 需要重写
init方法, allocWithZone方法, copyWithZone方法:
init方法, allocWithZone方法, copyWithZone方法:
static id _instance;
- (id)init
{
if (self = [super init]) {
// 加载资源
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
});
}
return self;
}
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
+ (id)copyWithZone:(struct _NSZone *)zone
{
return _instance;
}
而在MRC中, 因为需要手动释放内存, 但是如果真的释放了, 下次创建对象就会失败, 所以得多重写4个方法:
- (oneway void)release
{
}
- (id)autorelease
{
return _instance;
}
- (id)retain
{
return _instance;
}
- (NSUInteger)retainCount
{
return 1;
}
+ (id)copyWithZone:(struct _NSZone *)zone
{
return _instance;
}
这样就可以了, 但是如果经常用到, 而且让我们不用关心ARC或MRC环境, 最好还是写个头文件, 将这些代码用一个宏来表示.
在这之前, 先了解以下 :
a. 可以用宏来判断当前的环境(ARC or MRC)
#if __has_feature(objc_arc)
#else
//MRC
#endif
b. 宏后面如果要表示多行, 则可以跟上 , 即表明有
标记的都是属于这个宏的, 但是注意最后一行不能加上 .
标记的都是属于这个宏的, 但是注意最后一行不能加上 .
c. 宏里面, 可以用## 来拼接参数
下面是头文件:(Singleton.h)
// ## : 连接字符串和参数
#define singleton_h(name) + (instancetype)shared##name;
#if __has_feature(objc_arc) // ARC
#define singleton_m(name)
static id _instance;
+ (id)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:(struct _NSZone *)zone
{
return _instance;
}
#else // 非ARC
#define singleton_m(name)
static id _instance;
+ (id)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;
}
- (oneway void)release
{
}
- (id)autorelease
{
return _instance;
}
- (id)retain
{
return _instance;
}
- (NSUInteger)retainCount
{
return 1;
}
+ (id)copyWithZone:(struct _NSZone *)zone
{
return _instance;
}
使用方法:
//.h类
//引入这个宏文件
#import "Singleton.h"
@interface Object : NSObject
singleton_h(name)
@end
//.m类
@implementation Object
singleton_m(name)
@end