2010-01-11 50 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