1. 单例模式原理
1.1. 概念
系统中的一个类,只有一个实例,易于外界访问。
示例:
[[UIApplication sharedApplication] statusBarStyle];
[NSNotificationCenter defaultCenter];
[NSUserDefaults standardUserDefaults];
[NSfileManager defaultManager];
1.2. 针对解决的问题
全局共享。
1.3. 优缺点
共享信息,用于管理中心。
破坏了封装性,破坏了设计模式中的最少知识原则。
1.4. 简单的单例
+(instancetype)managerCenter{
static className*center = nil;
if (center == nil){
center = [[className alloc] init];
}
return center;
}
这种方案会导致多个位置同时访问时,都会进入if逻辑里面。
那么采取另外的方案:
+(instancetype)managerCenter{ static className*center = nil; static dispatch_once_t predicate; dispatch_once (&predicate, ^{ center = [[className alloc] init]; }); return center; }
第三种方案:
由于所有的类启动时都会调用+(void)initialize方法,所以,可以在里面处理:
+(void)initialize{ static className *center = nil; if(self == ([className class]){ center = [[calssName alloc] init]; } }
2. 编写严格的单例
#import "VGPathManager.h"
#pragma mark - 创建实例
static VGPathManager *center = nil;
static NSString *strClass = @"VGPathManager";
@implementation VGPathManager
+ (instancetype)managerCenter {
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
/**
* 这么做的原因是:在 init() 中会判断是否是本类,而不是子类
*/
center = (VGPathManager *)strClass;
center = [[VGPathManager alloc] init];
});
if (nil != center) {
if (FALSE == [center cantUsedBySubClass]) {
return nil;
}
}
return center;
}
- (instancetype)init {
NSString *string = (NSString *)center;
if ([string isKindOfClass:[NSString class]] == YES && [string isEqualToString:strClass]) {
self = [super init];
if (self) {
if (FALSE == [self cantUsedBySubClass]) {
return nil;
}
}
return self;
} else {
return nil;
}
}
/**
* 防止子类使用,如果是子类,则会是不同的名称
*/
- (BOOL) cantUsedBySubClass {
NSString *classString = NSStringFromClass([self class]);
if ([classString isEqualToString:strClass] == NO) {
return FALSE;
}
return TRUE;
}
@end
2.1. 防止继承
不允许子类也实现该实例,在请求单例的方法中的进行类的名称的判断。
2.2. 防止多个实例
一个类中只有一个实例,但是上面的例子并不能实现一个实例,因为还可以alloc一些实例。
3. 例子优化存储
用FastCoding把对象转换成NSData,然后存储到本地。
3.1. 用单例设计存储数据接口
单例就不用细说了,见上面的实现。
存储数据接口就是加上下面两个接口:
- (void)storeValue:(id)value withKey:(NSString *)key; - (id) valueWithKey:(NSString *) key;
3.2. 用单例接口隔离实现细节
- (void)storeValue:(id)value withKey:(NSString *)key { NSParameterAssert(value);//为空则崩溃 NSParameterAssert(key);//为空则崩溃 NSData *data = [FastCoder dataWithRootObject:value]; if (data) { [[NSUserDefaults standardUserDefaults] setObject:data forKey:key]; } } - (id)valueWithKey:(NSString *)key { NSParameterAssert(key);//为空则崩溃 NSData *data = [[NSUserDefaults standardUserDefaults] valueForKey:key]; return [FastCoder objectWithData:data]; }