1、在上一篇单例模式(一)中介绍过如何创建单例,那么接下来如何简化一下单例模式。之前的单例模式是这样的:
SpiderMan.h
#import@interface SpiderMan : NSObject
+ (instancetype)shanreSpiderMan;
@end
SpiderMan.m
#import "SpiderMan.h"
@implementation SpiderMan
static id _instance;
+ (id)allocWithZone:(struct _NSZone *)zone
{
if (_instance == nil) { // 防止频繁加锁
@synchronized(self) {
if (_instance == nil) { // 防止创建多次
_instance = [super allocWithZone:zone];
}
}
}
return _instance;
}
+ (id)shanreSpiderMan
{
if (_instance == nil) { // 防止频繁加锁
@synchronized(self) {
if (_instance == nil) { // 防止创建多次
_instance = [[self alloc] init];
}
}
}
return _instance;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instance;
}
@end
可以发现,要经常写这一东西:
if (_instance == nil) { // 防止频繁加锁
@synchronized(self) {
if (_instance == nil) { // 防止创建多次
_instance = [[self alloc] init];
}
}
}
这些代码其实可以用另外一种方式来实现,GCD中有一个方法是只执行一次的,即:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ });
使用该方法来代替以上代码可以简化许多:
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
详细代码也可以看github上的例子里的People类。
2、以上的单例都是在ARC环境下的,在非ARC环境下需要再做处理:
- (oneway void)release { }
- (id)retain { return self; }
- (NSUInteger)retainCount { return 1;}
- (id)autorelease { return self;}
-
(oneway void)release {} :为了防止对象被释放;
-
(id) retain {return self }: 为了防止产生新的对象;
-
(NSUInteger)retainCount {return 1;} :保证一个对象引用计数始终为1;
3、如果一个项目当中有非常多的单例类,对每个单例类都进行
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
+ (id)sharePeoper
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc]init];
});
return _instance;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instance;
}
这样子会非常繁琐,其实可以做相应地简化,简化的方法是:创建一个头文件,宏定义单例头文件和.m文件。如:
// .h文件
#define HMSingletonH + (instancetype)sharedInstance;
// .m文件
#define HMSingletonM \
static id _instance; \
\
+ (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:(NSZone *)zone \
{ \
return _instance; \
}
4、那么接下来需要解决的一个问题就是在ARC环境和MRC环境下如何使用宏定义来适配单例模式。方法还是比较简单的,因为可以使用
#if __has_feature(objc_arc) // arc环境
#else // mrc 环境
#endif
来判断是在ARC还是在MRC环境下。不多说,直接上代码(在新建的一个头文件里):
// .h文件
#define HMSingletonH(name) + (instancetype)shared##name;
// .m文件
#if __has_feature(objc_arc)
#define HMSingletonM(name) \
static id _instace; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super allocWithZone:zone]; \
}); \
return _instace; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [[self alloc] init]; \
}); \
return _instace; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instace; \
}
#else
#define HMSingletonM(name) \
static id _instace; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super allocWithZone:zone]; \
}); \
return _instace; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [[self alloc] init]; \
}); \
return _instace; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instace; \
} \
\
- (oneway void)release { } \
- (id)retain { return self; } \
- (NSUInteger)retainCount { return 1;} \
- (id)autorelease { return self;}
#endif
以后每次要使用到单例的时候,就导入该头文件,写上两句代码就OK了,例如Person单例:
.h
#import@interface Person : NSObject
ANSingletonH(Person)
@end
.m
#import "Person.h"
@implementation Person
ANSingletonM(Person)
@end
也可以到我的github上查看完整代码
网友评论