iOS - 單例創建的注意事項


單例創建的第一種寫法:多線程 dispatch_once

一般寫法:

#import <Foundation/Foundation.h>


@interface FNWaterMarkHelper : NSObject


+ (instancetype)sharedWaterMark;  

@end
#import "FNUserInfoManager.h"
static FNWaterMarkHelper *_showWaterMark = nil;

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


@end

輸出測試:

#import <Foundation/Foundation.h>  
#import "Downloader.h"  
  
int main(int argc, const char * argv[]) {  
    @autoreleasepool {  
        FNWaterMarkHelper *obj1 = [FNWaterMarkHelper sharedWaterMark];  
        NSLog(@"obj1 = %@", obj1);  
          
        FNWaterMarkHelper *obj2 = [FNWaterMarkHelper sharedWaterMark];  
        NSLog(@"obj2 = %@", obj2);  
          
        FNWaterMarkHelper *obj3 = [[FNWaterMarkHelper alloc] init];  
        NSLog(@"obj3 = %@", obj3);  
    }  
      
    return 0;  
}  

結果:

obj1 = <Downloader: 0x78f25be0>  
obj2 = <Downloader: 0x78f25be0>  
obj3 = <Downloader: 0x79225e00>  

解釋:

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

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

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

改進:

#import "FNUserInfoManager.h"
static FNWaterMarkHelper *_showWaterMark = nil;

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

+ (id)allocWithZone:(struct _NSZone *)zone {  
    return [FNWaterMarkHelper sharedWaterMark];  
}  
  
- (id)copyWithZone:(struct _NSZone *)zone {  
    return [FNWaterMarkHelper sharedWaterMark];  
}  

@end

輸出結果:

obj1 = <Downloader: 0x7ca42e70>  
obj2 = <Downloader: 0x7ca42e70>  
obj3 = <Downloader: 0x7ca42e70>  

搞定!

 

單例創建的第二種方法構造函數,不常用:

static PublicUtils *DefaultManager = nil;

+(instancetype)sharedUtils
{
    if (!DefaultManager)
        DefaultManager = [[self allocWithZone:NULL] init];
    
    return DefaultManager;
}

 


免責聲明!

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



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