iOS 单例
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]; }