开发者

Memoization in static Objective-C class

Say I have a class method like

+ (double)function:(id)param1 :(id)param2
{
   // I want to memoize this like...
   s开发者_开发知识库tatic NSMutableDictionary* cache = nil;
   //
   // test if (param1,param2) is in cache and return cached value, etc. etc
   //
}

Thanks!!


If you want to create the cache once and check against it, I generally use an +initialize method. This method is called before the first message sent to the class, so the cache would be created before +function:: (which, by the way, is a terrible selector name) could be called. In this case, I usually declare the cache variable in the .m file, but declaring it in the method definition may also work.


Edit: Adding an example at request of 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.
}

Obviously, if a value doesn't exist in the cache, you should have some code that adds the value. Also, I have no idea how you intend to combine param1 and param2 as the key for the cache, or how you'll store the value. (Perhaps +[NSNumber numberWithDouble:] and -[NSNumber doubleValue]?) You'll want to make sure you understand dictionary lookups before implementing such a strategy.


I use something like the following. Unlike the version posted by @Quinn Taylor, this version has the following properties:

  • Creates a NSAutoreleasePool to guarantee that a pool exists. Best to assume the worst when dealing with 'start-up' like code. Harmless if a pool already exists.
  • Creates cache exactly once:
    • Safe to call +initialize multiple times (may happen via sub-classing).
    • Multi-threaded safe. No matter how many threads concurrently call +initialize at the exact same time, cache is guaranteed to only be created once. The thread that 'wins' the atomic CAS retains cache, the threads that 'loose' autorelease their attempts.

If you want to be extremely conservative, you can add assertion checks that both pool and initCache are not NULL. Also note that this does nothing to ensure that cache is used in a multi-threaded safe way once it's been created.

#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;
}


Depending on what you're trying to do and whether thread safety is an issue, you may also want to consider a singleton class as in the answer to this earlier question.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜