单例模式
- 共享信息,管理中心
- 单例类基本是用来管理某种资源的,而这种资源是可以全局共享的
- 只有一个实例
Cocoa系统中的单例应用
[[UIApplication sharedApplication]statusBarStyle];
[[NSNotificationCenter defaultCenter]addObserver:<#(nonnull id)#>
selector:<#(nonnull SEL)#>
name:<#(nullable NSString *)#>
object:<#(nullable id)#>];
[[NSUserDefaults standardUserDefaults]setObject:<#(nullable id)#>
forKey:<#(nonnull NSString *)#>];
[NSFileManager defaultManager];
单例创建的三种方法
UserInfoManagerCenter
@interface UserInfoManagerCenter : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSNumber *age;
方法1. 任何类调用其他方法前,先调用此方法
+ (void)initialize {
static UserInfoManagerCenter *center = nil;
if (self == [UserInfoManagerCenter class]) {
center = [[UserInfoManagerCenter alloc] init];
}
}
方法2. 有弊端。如果AppDelegate里,也同时以此方法创建单例,程序就会奔溃
+ (instancetype)managerCenter {
static UserInfoManagerCenter *center = nil;
if (center == nil) {
center = [[UserInfoManagerCenter alloc] init];
}
return center;
}
方法3. 最佳
+ (instancetype)managerCenter {
static UserInfoManagerCenter *center = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
center = [[UserInfoManagerCenter alloc] init];
});
return center;
}
单例数据共享
AppDelegate: 在此创建单例并赋值
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UserInfoManagerCenter *center = [UserInfoManagerCenter managerCenter];
center.name = @"极客学院";
return YES;
}
ViewController: 在此获取单例的数据
UserInfoManagerCenter *center = [UserInfoManagerCenter managerCenter];
NSLog(@"%@", center.name);
编写严格的单例
防止子类继承
@implementation UserInfoManagerCenter
+ (instancetype)managerCenter {
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
center = [[UserInfoManagerCenter alloc] init];
});
// 防止子类使用
NSString *classString = NSStringFromClass([self class]);
if ([classString isEqualToString:@"UserInfoManagerCenter"] == NO) {
NSParameterAssert(nil);
}
return center;
}
确保实例对象只有一个
因为单例管理的是系统资源,一个对象非常耗资源,所以要避免不能用alloc init方法创建
#import "UserInfoManagerCenter.h"
static UserInfoManagerCenter *center = nil;
@implementation UserInfoManagerCenter
+ (instancetype)managerCenter {
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
center = (UserInfoManagerCenter *)@"UserInfoManagerCenter";
center = [[UserInfoManagerCenter alloc] init];
});
// 防止子类使用
NSString *classString = NSStringFromClass([self class]);
if ([classString isEqualToString:@"UserInfoManagerCenter"] == NO) {
NSParameterAssert(nil);
}
return center;
}
- (instancetype)init {
NSString *string = (NSString *)center;
if ([string isKindOfClass:[NSString class]] == YES && [string isEqualToString:@"UserInfoManagerCenter"]) {
self = [super init];
if (self) {
// 防止子类使用
NSString *classString = NSStringFromClass([self class]);
if ([classString isEqualToString:@"UserInfoManagerCenter"] == NO) {
NSParameterAssert(nil);
}
}
return self;
} else {
return nil;
}
}
@end
防止调用alloc init细节阐述
首先center的实际值设为一个字符串
center = (UserInfoManagerCenter *)@"UserInfoManagerCenter";
然后在随后调用的init里进行判断,只有经历过 + managerCenter方法的才能创建实例,如果直接调用allo init的,那返回是空值
- (instancetype)init {
NSString *string = (NSString *)center;
if ([string isKindOfClass:[NSString class]] == YES && [string isEqualToString:@"UserInfoManagerCenter"]) {
}
单例模式优化本地存储
第三方库:FastCoding
替换NSCoding协议, plist, JSON等,直接将数据存为NSData类型
下载地址:FastCoding
关闭ARC
用单例设计存储数据接口
- (void)storeValue:(id)value withKey:(NSString *)key;
- (id)valueWithKey:(NSString *)key;
用单例接口隔离实现细节
- (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];
}
在单例提供接口的基础上进行上层封装
封装前
StudentModel *student = [[StudentModel alloc] init];
student.name = @"A";
NSArray *array = @[[InfoModel new], [InfoModel new], [InfoModel new]];
student.datas = array;
//每次都要得到这个单例
[[StoreValue sharedInstance] storeValue:student withKey:@"FastCoding"];
封装后
StudentModel *student = [[StudentModel alloc] init];
student.name = @"A";
NSArray *array = @[[InfoModel new], [InfoModel new], [InfoModel new]];
student.datas = array;
[student storeValueWithKey:@"FastCoding"];
如何封装
新建category: StoreValue
@implementation NSObject (StoreValue)
//这样student对象就可以直接调用该方法来存储
- (void)storeValueWithKey:(NSString *)key {
[[StoreValue sharedInstance] storeValue:self withKey:key];
}
//studentModel可以直接调用类方法来存储
+ (id)valueByKey:(NSString *)key {
return [[StoreValue sharedInstance] valueWithKey:key];
}