iOS嚴謹單例寫法/可繼承單例

單例模式在iOS開發中可能算是最經常使用的模式之一了,可是因爲OC自己的語言特性,想要寫一個正確的單例模式相對來講比較麻煩. 今天就來講一說, 單例建立的方式和嚴謹的單例寫法及可繼承單例編寫.ios

基本單例的建立方式

方式一(普通建立方式)

SingleHandle.hatom

@interface SingleHandle : NSObject

//單例建立方法通常以 share, stand, main 開頭 + 當前類名
+(SingleHandle *)shareSingleHandle;

@end

SingleHandle.mspa

@implementation SingleHandle

//聲明靜態變量
static SingleHandle *singlehanle = nil;

+(SingleHandle *)shareSingleHandle
{
    //同步鎖  //防止一種極限的可能,第一個對象正在建立的時候,第二個對象就開始建立了,形成兩個對象
    @synchronized(self){
        if (singlehanle == nil) {
            singlehanle = [[SingleHandle alloc]init];
        }
        return singlehanle;
    }
}
@end

方式二(GCD 方式)

Singleton.h.net

@interface Singleton : NSObject

+(instancetype) shareInstance;

@end

Singleton.mcode

@implementation Singleton

static Singleton* instance = nil;

+(instancetype) shareInstance
{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init] ;
    }) ;

    return instance ;
}

@end

嚴謹的單例寫法探究

通常寫法

通常狀況下,可能咱們寫的單例模式是上面的方式, 這裏再也不贅述, 但這樣是不嚴謹的. 先來看一下到底不嚴謹的寫法缺點是什麼. 
以上面的方式二舉例:對象

Singleton* single1 = [Singleton shareInstance] ;
    NSLog(@"single1 = %@", single1) ;

    Singleton* single2 = [Singleton shareInstance] ;
    NSLog(@"single2 = %@", single2) ;

    Singleton* single3 = [[Singleton alloc] init] ;
    NSLog(@"single3 = %@", single3) ;

    NSLog(@"single4 = %@", [single3 copy]) ;

打印結果:繼承

single1 = < Singleton: 0x7ffb93743e80 > 
single2 = < Singleton: 0x7ffb93743e80 > 
single3 = < Singleton: 0x7ffb9373ecc0 > 
-[Singleton copyWithZone:]: unrecognized selector sent to instance 0x7ffb9373ecc0

能夠看到,當咱們調用shareInstance方法時獲取到的對象是相同的,可是當咱們經過alloc和init來構造對象的時候,獲得的對象倒是不同的。並且在 single4 這行註釋打開後, 會在此崩潰, 緣由如上. 內存

因此,咱們經過不一樣的途徑獲得不一樣的對象,顯然是不行的。咱們必需要確保對象的惟一性,因此咱們就須要封鎖用戶經過alloc和init以及copy來構造對象這條道路。ci

咱們知道,建立對象的步驟分爲申請內存(alloc)、初始化(init)這兩個步驟,咱們要確保對象的惟一性,所以在第一步這個階段咱們就要攔截它。當咱們調用alloc方法時,OC內部會調用allocWithZone這個方法來申請內存,咱們覆寫這個方法,而後在這個方法中調用shareInstance方法返回單例對象,這樣就能夠達到咱們的目的。拷貝對象也是一樣的原理,覆寫copyWithZone方法,而後在這個方法中調用shareInstance方法返回單例對象。開發

嚴謹的寫法

@implementation Singleton

static Singleton* instance = nil;

+(instancetype) shareInstance
{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        instance = [[super allocWithZone:NULL] init];
    }) ;

    return instance ;
}
+(id) allocWithZone:(struct _NSZone *)zone
{
    return [Singleton shareInstance] ;
}
-(id) copyWithZone:(struct _NSZone *)zone
{
    return [Singleton shareInstance] ;
}
@end

打印結果:

single1 = < Singleton: 0x7fe2e24a2880 > 
single2 = < Singleton: 0x7fe2e24a2880 > 
single3 = < Singleton: 0x7fe2e24a2880 > 
single4 = < Singleton: 0x7fe2e24a2880 >

這樣就是比較正確很嚴謹的寫法了.

可繼承單例探究

可繼承單例是指父類中寫下單例建立的方法, 當其自己類或其子類調用父類中的類建立的方法時, 能夠各自類建立各自類的單例. 因此, 在父類中寫的一個方法, 同時適用於其自己和其子類, 故稱做可繼承單例.

單例類 A :

@interface A : NSObject
@property (nonatomic,copy)NSString *a1;

+ (instancetype)sharedInstance;

@end


#import "A.h"
#import <objc/runtime.h>
@implementation A

+(instancetype)sharedInstance
{
    id instance = objc_getAssociatedObject(self, @"instance");

    if (!instance)
    {
        instance = [[super allocWithZone:NULL] init];
        NSLog(@"單例建立=====%@=====",instance);
        objc_setAssociatedObject(self, @"instance", instance, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return instance;
}
+(id) allocWithZone:(struct _NSZone *)zone
{
    return [self sharedInstance] ;
}
-(id) copyWithZone:(struct _NSZone *)zone
{
    Class selfClass = [self class];
    return [selfClass sharedInstance] ;
}
@end

單例類 B 和單例類 C 中無任何方法和屬性, 只是繼承於A類. 

執行下面的方法:

A *singleA = [A sharedInstance];
    B *singleB = [B sharedInstance];
    C *singleC = [C sharedInstance];

    singleA.a1 = @"aaa";
    singleB.a1 = @"bbb";
    singleC.a1 = @"ccc";

    NSLog(@"singleA = %p",singleA);
    NSLog(@"singleB = %p",singleB);
    NSLog(@"singleC = %p",singleC);

    NSLog(@"singleA.a1 = %@",singleA.a1);
    NSLog(@"singleB.b1 = %@",singleB.a1);
    NSLog(@"singleC.c1 = %@",singleC.a1);

打印結果:

單例建立=====< A: 0x7fc21282fb60 >===== 
單例建立=====< B: 0x7fc21282fcb0 >===== 
單例建立=====< C: 0x7fc210427190 >===== 
singleA = 0x7fc21282fb60 
singleB = 0x7fc21282fcb0 
singleC = 0x7fc210427190 
singleA.a1 = aaa 
singleB.a1 = bbb 
singleC.a1 = ccc
相關文章
相關標籤/搜索