單例模式

這篇文章的主要內容包括:
1、在ARC中完成一個單例模式的三步
2、在MRC中完成一個單例模式的三步
3、單例模式通用宏(最重要)

單例模式是一種常用的軟件設計模式。
在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中一個類只有一個實例,節約系統的資源。

  • 單例模式的應用場景

在整個程序中,共享一份資源,這個資源只被初始化一次。

  • 在ARC中完成一個單例模式一共有三步:

0.提供靜態全局變量
1.重寫allocWithZone
2.提供一個類方法
3.重寫copyWithZone和MutableCopyWithZone

#import "XMGTool.h"

@implementation XMGTool

//0.提供全局變量
static XMGTool *_instance;

//1.重寫alloc方法
+(instancetype)allocWithZone:(struct _NSZone *)zone{

//    懶加載 永遠只分配一次存儲空間
//    如果多個線程同時alloc,訪問同一塊資源,可能涉及線程安全的問題,所以我們可以加上一把互斥鎖
//    @synchronized (self) {
//        
//    }if(_instance==nil){
//        _instance=[super allocWithZone:zone];
//    }
//    方法二:GCD一次性代碼
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance=[super allocWithZone:zone];
    });

        return _instance;
}


//2.提供一個類方法
//類方法的好處在于:外界方便訪問;表明身份
//注意命名規范share+類名/default+類名
+(instancetype)shareTool{
    
    return [[self alloc]init];
    //這里alloc就調用了上面重寫的alloc方法 保證只創建一個對象
    
}


//3.重寫copy和mutable方法
-(id)copyWithZone:(NSZone *)zone{
    //對象方法,運行之前已經有對象存在了,所以直接返回就可以
    return _instance;
}

-(id)mutableCopyWithZone:(NSZone *)zone{
    return _instance;
}

@end

這樣,在控制器中不論用以下任何一種方式創建對象,地址都是相同的,因為只創建一次:

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    //1.重寫allocWithZone
    //單例模式就是不管過程中alloc init多少次 new多少次 都始終是那一個對象
    //單例模式的實現方法:重寫alloc方法
    XMGTool *t1=[[XMGTool alloc]init];
    XMGTool *t2=[[XMGTool alloc]init];
    XMGTool *t3=[XMGTool new];
    
    //2.提供一個類方法
    XMGTool *t4=[XMGTool shareTool];
    
    //3.重寫copyWithZone和MutableCopyWithZone
    //注意:這兩個方法都是對象方法
    XMGTool *t5=[t1 copy];
    XMGTool *t6=[t1 mutableCopy];

    
    NSLog(@"t1:%p----t2:%p----t3:%p----t4:%p----t5:%p----t6:%p",t1,t2,t3,t4,t5,t6);
}

  • 在MRC中實現單例模式也一共三步

非ARC模式事實上離我們已經很遙遠了
事實上,就是重寫release和retain以及retainCount方法
這里可以使用一個小技巧 ——條件編譯(注意,條件編譯不可以用在宏中)
進行判斷 如果不滿足ARC就執行else和endif之間的

//上接ARC的三個方法
#if __has_feature(objc_arc)
#else
//MRC
-(oneway void)release{
    
}

-(instancetype)retain{
    return _instance;
}

//一個約定俗成的習慣
-(NSUInteger)retainCount{
    return MAXFLOAT;
}
#endif
  • 單例模式通用宏

其實以上兩個單例模式都不好
下面介紹在 ARC、MRC都可以實現單例模式的通用宏
用它實現代碼的復用,也就是說把單例模式抽取出來,以后用到的時候,在類的h和m文件中包含這個宏就可以了

以下是宏中的代碼(條件判斷編譯不可以放在宏中):

 #define SingleH(name) +(instancetype)share##name;

#if __has_feature(objc_arc)
//ARC
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone{\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
        _instance=[super allocWithZone:zone];\
    });\
    return _instance;\
}\
+(instancetype)share##name{\
    return [[self alloc]init];\
    }\
-(id)copyWithZone:(NSZone *)zone{\
       return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone{\
    return _instance;\
}



#else
//MRC
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance=[super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(oneway void)release{\
}\
-(instancetype)retain{\
    return _instance;\
}\
-(NSUInteger)retainCount{\
    return MAXFLOAT;\
}

#endif


引用示例:


54D6E386-AE5D-4721-A6E1-B975F1D04F7D.png
C0BF99D7-831E-4905-A49E-5857374ED02F.png
E66A6E95-A367-4F03-A5DD-0D6E02180ECC.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 單例模式的作用 可以保證在程序運行過程,一個類只有一個實例,而且該實例易于供外界訪問 從而方便地控制了實例個數,并...
    JonesCxy閱讀 385評論 0 0
  • 一. ARC環境下的單例模式 單例模式的基本概念單例, 顧名思義, 即在整個程序中, 某一個類只有唯一一個實例, ...
    面糊閱讀 765評論 0 50
  • 近年來各種理論層出不窮,文章里不帶點“藍平長二”之類都不好意思讓人看。 為免(了)浪費諸君的寶貴時間,特此對名詞做...
    SJTU_CTR閱讀 161評論 0 1
  • 周天奶奶給我買了一本優秀作文選,我覺得這篇作文很好,在這里分享給大家。 作文的題目是《我會給動畫配...
    徐雨恒閱讀 222評論 0 0
  • 今晚被同事嗆到哭,難受得無法自抑。 今天的狀態很差,繃緊了神經辦理業務。旁邊一位同事在看考試題準備周末統考,兩位在...
    素素_sky閱讀 382評論 0 0