【iOS - OC】OC基礎-單例的實現 & 提醒本身注意多線程問題

作客戶端開發應當時刻考慮多線程問題。我最初是作前端開發的,在這方面考慮得每每不夠。謹記。前端

單例的常見寫法

單例的常見寫法其實就兩種安全

1. 依賴鎖

+ (id)sharedInstance {  
    static testClass *sharedInstance = nil;  
    @synchronized(self) {  
        if (!sharedInstance) {  
            sharedInstance = [[self alloc] init];  
        }  
    }  
    return sharedInstance;  
}

2. 依賴dispatch_once

+ (id)sharedInstance {  
    static testClass *sharedInstance = nil;  
    static dispatch_once_t once;  
    dispatch_once(&once, ^{  
        sharedInstance = [[self alloc] init];  
    });  
    return sharedInstance;  
}

dispatch_once的寫法更推薦一些。一方面是性能上好一點,另外一方面是語義上更直觀。once,執行一次嘛。網絡

無論是用鎖仍是dispatch_once,本質上都是爲了不單例建立過程出現線程安全問題。多線程

更進一步,咱們常常會有懶加載某些屬性的寫法:框架

- (id<InterfaceEngineA>)engineA
{
    if (_engineA == nil) {
        _engineA = [EngineA new];
    }
    
    return _engineA;
}

其實跟單例的實現是相似的,這種時候要格外注意線程安全問題。若是存在多線程場景,必定要作好保護性能

- (id<InterfaceEngineA>)engineA
{
    @synchronized(self) {
        if (_engineA == nil) {
            _engineA = [EngineA new];
        }
    }
    return _engineA;
}

一些廢話

多線程問題的表現多是各類各樣難以預料的。這裏我遇到的是,_engineA在多線程場景下小几率被重複建立,其實例1在init時註冊了網絡層命令字cmd1的回包,而這個網絡層框架的實現是,只接受第一個註冊這一命令字的對象。致使實例2註冊失敗。後面調用實例2發送請求,回包都被實例1接收了。從日誌上看,一切都挺正常的。可是下次取數據就是取不到。學習

這個bug第一次提過來的時候,沒分析出根本緣由,只在表面上作了保護。結果第二次提過來才真正改掉。spa

丟人吶。仍是要好好學習纔是。線程

相關文章
相關標籤/搜索