2010-01-11 72 views
1

說我有一個類的方法一樣記憶化靜態Objective-C類

+ (double)function:(id)param1 :(id)param2 
{ 
    // I want to memoize this like... 
    static NSMutableDictionary* cache = nil; 
    // 
    // test if (param1,param2) is in cache and return cached value, etc. etc 
    // 
} 

謝謝!

+0

複製http://stackoverflow.com/questions/554969/using-static-keyword-in-objective-c-when-defining-a-cached-variable – joshperry 2010-01-12 01:19:37

回答

5

如果你想創建緩存一次並檢查它,我通常使用+initialize方法。這個方法在第一個消息發送到類之前被調用,所以緩存將在+function::之前被創建(順便說一下,這是一個可怕的選擇器名稱)可以被調用。在這種情況下,我通常在.m文件中聲明緩存變量,但是在方法定義中聲明它也可以。


編輯:添加一個例子,在OP的要求:

// MyClass.m 

static NSMutableDictionary* cache; 

+ (void) initialize { 
    cache = [[NSMutableDictionary alloc] init]; 
} 

+ (double) cachedValueForParam1:(id)param1 param2:(id)param2 { 
    // Test if (param1,param2) is in cache and return cached value. 
} 

顯然,如果一個值不緩存中,你應該有一些代碼,增加了價值。另外,我不知道你打算如何將param1param2作爲緩存的關鍵字,或者你將如何存儲該值。 (也許+[NSNumber numberWithDouble:]-[NSNumber doubleValue]?)在實施這樣的策略之前,你需要確保你理解字典查找。

+0

顯然名稱是通用的笑。你能提供一個在+初始化中創建變量的例子,因爲它不是一個實例成員變量。 – DevDevDev 2010-01-11 23:47:45

+0

我不會推薦這種方法。它不是多線程安全的,多次調用'initialize'也是安全的(這可以通過調用'[super initialize]'的子類來實現)。 – johne 2010-01-12 03:10:31

+2

當然,有些方法可以使方法更「安全」,我只是不想過分複雜或壓倒OP。說實話,這是一個緩存,所以在替換現有的字典時會導致錯誤並導致泄漏,但解決這個問題很容易。例如,我的'+ initialize'通常在做任何事之前檢查(並且經常同步)'[self class]'。最佳實踐是美好的,但是我們不要在一個簡單的問題上拋出每個可能的錯誤情況,我們? – 2010-01-12 04:33:17

0

根據你想要做什麼以及線程安全是否是一個問題,你可能還想考慮一個單例類,如the answer to this earlier question

+0

也檢查出http://stackoverflow.com/questions/1986736/nsmutabledictionary-thread-safety NSMutableDictionary線程安全。 – corprew 2010-01-12 00:36:10

2

我使用類似下面的東西。與@Quinn Taylor發佈的版本不同,此版本具有以下屬性:

  • 創建NSAutoreleasePool以確保存在池。在處理諸如代碼的「啓動」時最好假設最差。如果游泳池已經存在,則無害。
  • 創建cache恰好一次:
    • 安全地調用+initialize多次(通過子類可能發生)。
    • 多線程安全。不管有多少線程同時在同一時間呼叫+initializecache保證只能創建一次。 '贏得'原子CAS的線程保留cache,這是'鬆'autorelease他們的嘗試的線程。

如果你想成爲非常保守,你可以添加斷言檢查這兩個poolinitCacheNULL。另外請注意,這不會確保cache一旦創建就以多線程安全的方式使用。

#include <libkern/OSAtomic.h> 

static NSMutableDictionary *cache; 

+ (void)initialize 
{ 
    NSAutoreleasePool *pool  = [[NSAutoreleasePool alloc] init]; 
    NSMutableDictionary *initCache = [[[NSMutableDictionary alloc] init] autorelease]; 
    _Bool    didSwap = false; 

    while((cache == NULL) && ((didSwap = OSAtomicCompareAndSwapPtrBarrier(NULL, initCache, (void * volatile)&cache)) == false)) { /* Allows for spurious CAS failures. */ } 
    if(didSwap == true) { [cache retain]; } 

    [pool release]; 
    pool = NULL; 
} 
+1

+1這些都是很好的支票,以及我自己的代碼。爲了簡單起見,我將它們排除在外,但它們是合乎邏輯的擴展。自動釋放池對我來說是一種折騰,因爲我總是在'main()'中使用,但如果第三方使用其代碼,則可能適用。對於子類,我通常用'-isMemberOfClass:'進行保護,爲了簡單起見,對於多線程,我在'[self class]'上使用@synchronized塊。儘管如此,還是很好的一個完整答案。 – 2010-01-12 03:28:38