Search code examples
objective-ccocoa-touchios5automatic-ref-countingretaincount

automatic reference counting (ARC) and retainCount


I am in the process of converting my project to use ARC, and ran into a special problem. I have a class that manages a cache of files that are downloaded from the network. Each file is stored in the iPhone filesystem, and an associated object is kept in my manager class for it. Other objects that want to use a file, request my manager for a cache object, and retain that for as long as they need the file.

But once in a while, the manager cleans up the cache, removing old files. Of course, it should not remove files that are in use at that moment. Before ARC, I detected that by using the retainCount of the associated object:

// if retainCount is 1 then only the cache has a reference to it
if( obj.retainCount <= 1 ) {
    [obj deleteFile];
    [cache removeObject:obj];
}

That worked perfectly [and yes, I know about the warnings about unreliability of retainCount, but in my experience, if retainCount > 1 you know for sure that more than one object has retained it]

However, with ARC, you are not allowed to use retainCount anymore. I could introduce my own retain counting mechanism, and require all objects that use files to explicitly retain and release the file objects. But that is errorprone, and it is exactly the kind of thing that ARC is supposed to solve.

Do you know a better way to achieve the same thing?


Solution

  • This feature is best handled by NSCache and NSDiscardableContent. This uses explicit start and end calls which allows you to maintain strong references to things you don't necessarily need kept around (because you'll recreate them automatically). Using NSCache for this also gets you other advantages, such as automatic dumping of discardable content even when you're suspended. Without something like NSCache, you would be killed when memory gets low rather than letting you dump your excess cache.

    That said, you've built another system. This particular problem is what weak references are for. Your cache should maintain a weak reference to the objects rather than a strong reference. There are several approaches discussed in Non-retaining array for delegates. I personally prefer the NSValue solution. The approved answer sounds great and simple, but you need to understand ARC and CFArray pretty well in order to use it correctly. The NSValue solution is much less tricky.

    Ideally, if your file objects know they are cached, they can tell the cache to remove them during their dealloc. Otherwise, you can periodically clear out empty values from the array.