How can I maintain a global object cache? (or NSMutableSet without saving content)

I have an iPhone app that deals with a subset of 25,000 locations at any given time.

I would like to preserve cache locations so that I know that if one part of my application updates a location, every other part that knows about that location will see the update.

My naive implementation creates an NSMutableSet to hold references to cached locations.

Methods for finding new locations will check the cache first and return the cached object, or if the location is not in the cache, they will create a new object and add it to the cache.

The problem is, how can I free objects that are no longer needed?

NSMutableSet will keep that location, so keepCount will never go to zero and dealloc will never get called.

Is there a kosher method to handle the release script? Is there any other pattern for this that I am not aware of.

(and CoreData is not an option at the moment, but I understand it does handle it).

Thank,

+2


source to share


5 answers


On the desktop, you can do this with an NSPointerSet, on the iPhone, it's a little more complicated.

You can use CoreFoundation to create a non-holding set if you really want:

//Default callbacks
CFSetCallBacks callbacks = kCFTypeSetCallBacks;

//Disable retain and release
callbacks.retain = NULL;
callbacks.release = NULL;

cachedPlaces = (NSMutableSet *)CFSetCreateMutable(kCFAllocatorDefault,
                                        0,
                                        &callbacks);

      



This makes a non-holding set. Note that you still need to remove the objects from the set when they are released, otherwise you will have stale pointers in your set, causing the tree to crash. Therefore, in the objects that you add to the set, you need to dealloc something like this:

- (void)dealloc {
  [cachedPlaces removeObject:self];

  [super dealloc];
}

      

This is really fine for purely memory cache of existing references, if you need to move stuff to and from disk as well, then CoreData will basically take care of all of this for you.

+3


source


You can use it NSMutableSet

as a cache and rely on the fact that any object it contains with a persistence of 1 belongs only to the cache. So any object with a hold value of 1 should be removed, it's easy to do:

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"retainCount > 1"];
[cachedPlaces filterUsingPredicate:predicate];

      



Do this on a timer or whenever space is added and / or removed if not too often. You can also make the predicate static to avoid generating a new instance every time.

+1


source


Use master data if you can deploy it on iPhone OS 3.0 or higher, or use SQLite for iPhoneOS 2.x. Either way, you can use a database to store your data, and you can make queries to get fresh datasets.

0


source


As of iOS 4.0, the correct way to do this is to use NSCache

. It can automatically clean up objects when the system sends low memory alert. You can also set limits on the size of the cache.

NSCache class reference

0


source


This question is old, but I recently ran into a similar problem. I believe that using NSHashTable might fit the requirements of this situation.

NSHashTable performs better than NSCache or NSSet because it can weakly reference your instances, so once all references are removed, the instance is automatically removed from the NSHashTable thanks to ARC. This works like a just-in-time caching technique, storing only those objects that are stored elsewhere due to strong links.

Considering that you have multiple parts of your application that could add links, using an NSHashTable as the Flyweight Pattern could be useful. The second part of the Flyweight pattern requires a factory, the factory will be responsible for checking the instance in the pool, adding it to the pool if not found, and then returning the merged instance.

0


source







All Articles