How can I get an array of zeroing weak references under ARC? I don't want the array to retain the objects. And I'd like the array elements either to remove themselves when they're deallocated, or set those entries to nil.
Similarly, how can I do that with a dictionary? I don't want the dictionary to retain the values. And again, I'd like the dictionary elements either to remove themselves when the values are deallocated, or set the values to nil. (I need to retain the keys, which are the unique identifiers, at least until the corresponding values are deallocated.)
These two questions cover similar ground:
But neither is asking for zeroing references.
Per the documentation, neither NSPointerArray nor NSHashMap support weak references under ARC. NSValue's nonretainedObjectValue will not work either, as it is non-zeroing.
The only solution I see is to create my own NSValue-like wrapper class with a (weak)
property, as this answer mentions, near the end. Is there a better way I'm not seeing?
I'm developing for OS X 10.7 and iOS 6.0.
Here's code for an a zeroing weak-referencing wrapper class. It works correctly with NSArray, NSSet, and NSDictionary.
The advantage of this solution is that it's compatible with older OS's and that's it simple. The disadvantage is that when iterating, you likely need to verify that -nonretainedObjectValue
is non-nil before using it.
It's the same idea as the wrapper in the first part of Cocoanetics' answer, which uses blocks to accomplish the same thing.
WeakReference.h
@interface WeakReference : NSObject {
__weak id nonretainedObjectValue;
__unsafe_unretained id originalObjectValue;
}
+ (WeakReference *) weakReferenceWithObject:(id) object;
- (id) nonretainedObjectValue;
- (void *) originalObjectValue;
@end
WeakReference.m
@implementation WeakReference
- (id) initWithObject:(id) object {
if (self = [super init]) {
nonretainedObjectValue = originalObjectValue = object;
}
return self;
}
+ (WeakReference *) weakReferenceWithObject:(id) object {
return [[self alloc] initWithObject:object];
}
- (id) nonretainedObjectValue { return nonretainedObjectValue; }
- (void *) originalObjectValue { return (__bridge void *) originalObjectValue; }
// To work appropriately with NSSet
- (BOOL) isEqual:(WeakReference *) object {
if (![object isKindOfClass:[WeakReference class]]) return NO;
return object.originalObjectValue == self.originalObjectValue;
}
@end