1

说我有一个类方法

+ (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
   //
}

谢谢!!

4

3 回答 3

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]?)在实施这样的策略之前,您需要确保您了解字典查找。

于 2010-01-11T23:45:20.923 回答
2

我使用类似下面的东西。与@Quinn Taylor 发布的版本不同,此版本具有以下属性:

  • 创建一个NSAutoreleasePool以保证池存在。在处理“启动”之类的代码时,最好假设最坏的情况。如果游泳池已经存在,则无害。
  • 只创建cache一次:
    • 安全调用+initialize多次(可能通过子分类发生)。
    • 多线程安全。无论有多少线程同时调用+initializecache都保证只创建一次。“赢得”原子 CAS 的线程保留cache,“松散”autorelease他们的尝试的线程。

如果你想非常保守,你可以添加断言检查两者poolinitCache不是NULL。另请注意,这并不能确保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;
}
于 2010-01-12T03:08:41.437 回答
0

根据您要执行的操作以及线程安全是否是一个问题,您可能还需要考虑一个单例类,如对前面问题的回答

于 2010-01-12T00:35:03.363 回答