Reputation: 6346
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?
Upvotes: 2
Views: 2692
Reputation: 12095
Not sure if this can be applied to your needs, but are you aware of Associative References? These allow you to attached slave objects to a master object, so that the slave object lives as long as the master lives. Not only allows this to attach objects to an object you do not have control over, but you can also learn about their end-of-life.
I wonder if you could use this to monitor your "obj" by attaching a custom class object to it, and that custom class' dealloc would be called if the "obj" gets deallocated. In that custom dealloc you can then perform the file removal.
Upvotes: 0
Reputation: 299595
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.
Upvotes: 5
Reputation: 10045
Just set up some int variable in your object's implementation, increment it each time the object is being retained and override its dealloc method to decrement it. The same retain count, but it's only good for custom objects.
Upvotes: 0