Cowboy Tech

iOS设计模式-单例

单例模式

  1. 共享信息,管理中心
  2. 单例类基本是用来管理某种资源的,而这种资源是可以全局共享的
  3. 只有一个实例

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