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

 

3.3. 在单例提供接口的寄出去进行上层封装

posted on 2015-12-01 14:42  大木哥  阅读(227)  评论(0编辑  收藏  举报

导航