简体   繁体   中英

How can I maintain a global cache of objects? (or a NSMutableSet w/o retaining contents)

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

I'd like to maintain a cache of places so that I know that if one part of my application updates a place, every other part that knows about that place sees the update.

My naive implementation is create an NSMutableSet to store references to the cached places.

Methods that find new places will first check the cache and return the cached object or if the place isn't in the cache, they will create a new place object and add it to the cache.

The problem is how do I release objects that are no longer needed?

The NSMutableSet will retain the place so the retainCount will never go to zero and dealloc will never be called.

Is there a kosher method to handle the release scenario? Is there some other pattern for doing this that I'm not aware of.

(and CoreData is not an option at this point, but I understand that it handles this).

Thank you,

On the desktop you can do this with NSPointerSet, on the iPhone it is a bit more difficult.

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

//Default callbacks
CFSetCallBacks callbacks = kCFTypeSetCallBacks;

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

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

That makes a non-retaining 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 that will cause you to crash on a deref. So in the objects you are adding to the set you need a dealloc something like this:

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

  [super dealloc];
}

This is only really suitable for a purely in memory cache of extant references, if you need to also move stuff to and from the disk then CoreData basically takes care of all of this for you.

You could use NSMutableSet as cache and rely on the fact that any object it contains with a retain count of 1 is only owned by the cache. Thus any object with a retain count of 1 should be removed, this is easily done:

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

Do this on a timer, or whenever aa place is added and/or removed if that is not too often. You could also make the predicate a static to avoid generating anew instance every time.

Use Core Data if you can deploy to iPhoneOS 3.0 or greater, or use SQLite for iPhoneOS 2.x. Either way you'll be able to use a database to store your data, and you'll be able to do queries to get fresh data sets.

This question is old, but I recently came across a similar issue. I believe using NSHashTable can fit the requirements of this situation.

NSHashTable works better than NSCache or NSSet because it can hold weak references to your instances, so that once all references are dropped the instance is automatically removed from the NSHashTable thanks to ARC. This works as a kind of 'Just-in-Time' caching method, only retaining objects held elsewhere by strong references.

Considering that you have multiple parts of the application that could be adding references, using the NSHashTable as the Flyweight Pool of the Flyweight Pattern could be useful. The second part of the Flyweight pattern requires a factory, the factory would be responsible for checking for the instance in the pool, adding it to the pool if it's not found, then returning the pooled instance.

As of iOS 4.0, the proper way to do this is to use an NSCache . It can automatically purge objects when the system sends a low-memory warning. You can also set limits on the cache size.

NSCache Class Reference

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM