1. 程式人生 > >OC怎麼正確的寫單例

OC怎麼正確的寫單例

今天偶然看到一篇文章,有所感觸,這才發現寫了好久的單例竟然並沒有寫正確,研究了一下,總結如下:

@interface MySingle() <NSCopying, NSMutableCopying>
@end

@implementation MySingle

+ (instancetype)sharedInstance {
    static MySingle *single = nil;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"dispatch_once");
        single = [[super allocWithZone:NULL] init];
        
        // 下面程式碼進行當前類的初始化操作
        [single initSelf];
    });
    
    NSLog(@"shared called");
    
    return single;
}

// 初始化程式碼
- (void)initSelf {
    self.myName = @"OK";
}

// 不能使用下面這個類進行初始化,否則會陷入死迴圈,或會使用得外部呼叫[[xx alloc] init] 會再次觸發這個方法
//- (instancetype)init {
//    NSLog(@"init called");
//    _myName = @"This is it.";
//    return self;
//}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    NSLog(@"allocWithZone");
    return [MySingle sharedInstance];
}

- (instancetype)copyWithZone:(NSZone *)zone {
    NSLog(@"copyWithZone");
    return self;
}

- (instancetype)mutableCopyWithZone:(NSZone *)zone {
    NSLog(@"mutableCopyWithZone");
    return self;
}

@end

使用時,下面幾種方式都能訪問到唯一的單例物件,且初始化方法也只會被呼叫一次,完美,收工。

    MySingle *allIN = [[MySingle alloc] init];
    NSLog(@"init:%@, name=%@", allIN, allIN.myName);
    
    MySingle *the = [MySingle sharedInstance];
    
    MySingle *copyIt = [the copy];
    NSLog(@"c:%@, name=%@", copyIt, copyIt.myName);
    
    NSLog(@"m:%@", [the mutableCopy]);

需要注意的是, 上面sharedInstance中寫初始化時使用的是super allocWithZone, 這裡不能寫成self allocWithZone,否則會引發迴圈。