设计模式

单例模式(二)

2016-05-02  本文已影响40人  ef463f819996

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;}

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上查看完整代码

上一篇下一篇

猜你喜欢

热点阅读