Objective-c單例模式的正確寫法


一般情況下,可能我們寫的單例模式是這樣的:

Ios代碼    收藏代碼
  1. #import <Foundation/Foundation.h>  
  2.   
  3. @interface Downloader : NSObject  
  4.   
  5. + (instancetype)sharedDownloader;  
  6.   
  7. @end  
  8.   
  9.   
  10. #import "Downloader.h"  
  11.   
  12. @implementation Downloader  
  13.   
  14. static Downloader *_sharedDownloader = nil;  
  15.   
  16. + (instancetype)sharedDownloader {  
  17.     static dispatch_once_t onceToken;  
  18.     dispatch_once(&onceToken, ^{  
  19.         _sharedDownloader = [[self alloc] init];  
  20.     });  
  21.       
  22.     return _sharedDownloader;  
  23. }  
  24.   
  25. @end  

 

具體使用:

Ios代碼    收藏代碼
  1. #import <Foundation/Foundation.h>  
  2. #import "Downloader.h"  
  3.   
  4. int main(int argc, const char * argv[]) {  
  5.     @autoreleasepool {  
  6.         Downloader *obj1 = [Downloader sharedDownloader];  
  7.         NSLog(@"obj1 = %@", obj1);  
  8.           
  9.         Downloader *obj2 = [Downloader sharedDownloader];  
  10.         NSLog(@"obj2 = %@", obj2);  
  11.           
  12.         Downloader *obj3 = [[Downloader alloc] init];  
  13.         NSLog(@"obj3 = %@", obj3);  
  14.     }  
  15.       
  16.     return 0;  
  17. }  

 

輸出結果:

Ios代碼    收藏代碼
  1. obj1 = <Downloader: 0x78f25be0>  
  2. obj2 = <Downloader: 0x78f25be0>  
  3. obj3 = <Downloader: 0x79225e00>  

 

可以看到,當我們調用sharedDownloader方法時獲取到的對象是相同的,但是當我們通過alloc和init來構造對象的時候,得到的對象卻是不一樣的。

那么問題就來了,我們通過不同的途徑得到不同的對象,顯然是不行的。我們必須要確保對象的唯一性,所以我們就需要封鎖用戶通過alloc和init以及copy來構造對象這條道路。

 

創建對象分為申請內存(alloc)、初始化(init)這兩個步驟,我們要確保對象的唯一性,因此在第一步這個階段我們就要攔截它。當我們調用alloc方法時,OC內部會調用allocWithZone這個方法來申請內存,我們覆寫這個方法,然后在這個方法中調用sharedDownloader方法返回單例對象,這樣就可以達到我們的目的。拷貝對象也是同樣的原理,覆寫copyWithZone方法,然后在這個方法中調用sharedDownloader方法返回單例對象。

Ios代碼    收藏代碼
  1. #import "Downloader.h"  
  2.   
  3. @implementation Downloader  
  4.   
  5. static Downloader *_sharedDownloader = nil;  
  6.   
  7. + (instancetype)sharedDownloader {  
  8.     static dispatch_once_t onceToken;  
  9.     dispatch_once(&onceToken, ^{  
  10.         _sharedDownloader = [[super allocWithZone:NULL] init];  
  11.     });  
  12.       
  13.     return _sharedDownloader;  
  14. }  
  15.   
  16. + (id)allocWithZone:(struct _NSZone *)zone {  
  17.     return [Downloader sharedDownloader];  
  18. }  
  19.   
  20. - (id)copyWithZone:(struct _NSZone *)zone {  
  21.     return [Downloader sharedDownloader];  
  22. }  
  23.   
  24. @end  

 

輸出結果:

Ios代碼    收藏代碼
  1. obj1 = <Downloader: 0x7ca42e70>  
  2. obj2 = <Downloader: 0x7ca42e70>  
  3. obj3 = <Downloader: 0x7ca42e70>  

 

可以看到獲取到的對象都是一樣的了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM