4

我最近遇到了一個問題,我只想要一個特定對象的一個​​實例存在,並且只存在它執行特​​定操作所需的短暫時間。它的操作是異步的,所以如果我沒有引用它,ARC會在運行循環結束時將其解除分配。如果我堅持使用它,我需要委託回調或通知來了解它何時完成釋放它。自毀單身設計模式iOS

該對象需要下載多個圖像和其他數據並將其緩存到磁盤。由於緩存限制大約24小時,因此當它不緩存項目時,我不希望它浪費內存。我也不需要任何反饋;我希望它能夠完成它的任務,並且完成它自己。

我想出了一個我很喜歡的設計模式。從那以後,我在其他幾個項目中使用過它,並且很奇怪它是否是一個衆所周知的分析模式,我只是不知道(自毀單身?)。我想知道,所以我可以意識到我目前沒有看到任何潛在的陷阱。

我也非常有興趣聽到你們可能有任何關於爲什麼這是一個糟糕的設計的輸入。

的設計是這樣的(這是ARC,但非弧可以工作太多,如果你通過發佈一個類的方法單身):因爲它沒有

全局靜態對象(不是一個真正的單生活的全部時間)

static MySelfDestructingClass* singleton; 

一個單一的公共類方法

+ (void)downloadAndCacheDataIfNeeded 
    { 
     //Force synchronized access 
     @synchronized(singleton){ 
      //We are already doing something, return 
      if(singleton){ 
      return; 
      } 
      NSDate* lastCacheDate = [[NSUserDefaults standardDefaults] objectForKey:kKeyForLastUpdate]; 
      if([[NSDate date] timeIntervalSinceDate:lastCacheDate] > kCacheLimit){ 
       //Our cache is out of date, we need to update 
       singleton = [[self alloc] init]; 
       [singleton downloadAndCache]; 
      } 
     } 
    } 

現在我們的實例方法,我們需要我們的對象還活着,因此要求能回來:

 - (void)downloadAndCache 
     { 
       //This would probably be a delegate, but for simplicity of this example it's a notification 
       [[NSNotificationCenter defaultCenter] addObserver:self forNotificationWithName:NotificationSomeRequestDidSucceed selector:@selector(someCustomRequestDidSucceed:withData:) object:nil]; 
       [SomeCustomRequest makeRequestWithURL:@"http://www.someURL.com"]; 

     } 

     - (void)someCustomRequestDidSucceed:(SomeCustomRequest *)request withData:(NSDictionary *)dictionary 
     { 

      //Do whatever we need to in order to save our data, or fire off image download requests etc... 
      .... 


      //Set our lastUpdated time in NSUserDefaults 
      [[NSUserDefaults standardDefaults] setObject:[NSDate date] forKey:kKeyForLastUpdate]; 

      //Remove our observer 
      [NSNotificationCenter defaultCenter] removeObserver:self name:NotificationSomeRequestDidSucceed object:nil]; 

      //Release ourselves (ok not really, but tell arc we can be released) 
      singleton = nil; 
     } 

這樣,所有我必須做的其他任何地方的應用是:

 [MySelfDestructingClass downloadAndCacheDataIfNeeded]; 

現在,這個對象將下載的東西,如果它需要和釋放本身當它完成,或在不創建自己所有。它也不會開始下載數據兩次。

我知道這個設計在擴展性和功能上有侷限性,但對於這樣的一個實例,以及我用過的其他實例,我發現它非常有用。

+0

對,我的觀點是,它不是一個單身人士,因爲它並不適用於應用程序的生命週期。但它確實遵循單例的「一次只記錄一個內存實例」的要求。這就是爲什麼我想知道什麼是自包含和託管類,只能有一個現有的實例被稱爲?自我毀滅Singleton是我想不到的唯一方式來描述它。 – 2012-04-20 05:41:08

+1

爲了限制討論,我將對此作出我的最後評論並刪除我的上述評論。無論哪種方式,這都有點違背穀物,這不一定是壞事。我有點擔心只是將它設置爲零,但我會說,如果您要將它用作標準庫或其他東西,請將其設置爲非ARC並使用明確的保留釋放循環。 – CodaFi 2012-04-20 05:43:51

+1

我喜歡它。我沒有看到這個實現有任何問題。儘管我不同意@CodaFi。我認爲讓這個非ARC明確地調用保留和釋放調用是不對的,也不是必要的。如果你願意,它可以是非ARC,但我不會那樣做。 – 2012-04-20 22:27:49

回答

1

這是很常見的使用塊。考慮類似的東西(雖然我可能會處理多個調用不同的...)

void ExecuteWithMySingleSelfDestructingObject(void(^block)(MySelfDestructingClass *object)) { 
    static MySelfDestructingClass* singleton; 
    @synchronized(singleton) { 
     if (singleton) { 
      // To get past the synchronization primitive, this must be a recursive call. 
     } 
     // Whatever other conditions you want to have (like your date check) 
     singleton = [[MySelfDestructingClass] alloc] init]; 
     @try { block(singleton); } 
     @finally { singleton = nil; } 
    } 
} 

注雙異常處理(嘗試/終於加什麼@Synchronized不 - 可能要改變......

然後做任何你想用塊...

ExecuteWithMySingleSelfDestructingObject(^(MySelfDestructingClass *object){ 
    // Do whatever I want with the singleton instance that has 
    // been given to me as <object> 
}); 

當然,也可能是一個類的方法...

+ (void)performBlock:(void(^)(MySelfDestructingClass *object))block { 
    static MySelfDestructingClass* singleton; 
    @synchronized(singleton) { 
     if (singleton) { 
      // To get past the synchronization primitive, this must be a recursive call. 
     } 
     // Whatever other conditions you want to have (like your date check) 
     singleton = [[self] alloc] init]; 
     @try { block(singleton); } 
     @finally { singleton = nil; } 
    } 
} 

[MySelfDestructingClass performBlock:^(MySelfDestructingClass *object){ 
    // Do whatever I want with the singleton instance that has 
    // been given to me as <object> 
}]; 

我希望這是有道理的(我自由輸入它,所以語法可能會有所不同,但你應該明白)。