The solutions to use a NSValue helper or to create a collection (array, set, dict) object and disable its Retain/Release callbacks are both not 100% failsafe solutions with regard to using ARC.
As various comments to these suggestions point out, such object references will not work like true weak refs:
A "proper" weak property, as supported by ARC, has two behaviors:
- Doesn't hold a strong ref to the target object. That means that if the object has no strong references pointing to it, the object will be deallocated.
- If the ref'd object is deallocated, the weak reference will become nil.
Now, while the above solutions will comply with behavior #1, they do not exhibit #2.
To get behavior #2 as well, you have to declare your own helper class. It has just one weak property for holding your reference. You then add this helper object to the collection.
Oh, and one more thing: iOS6 and OSX 10.8 supposedly offer a better solution:
[NSHashTable weakObjectsHashTable][NSPointerArray weakObjectsPointerArray][NSPointerArray pointerArrayWithOptions:]
These should give you containers that hold weak references (but note matt's comments below).
An example (updated 2 Feb 2022)
#import <Foundation/Foundation.h>static BOOL didDealloc = NO;@interface TestClass : NSObject@end@implementation TestClass-(void)dealloc { didDealloc = YES;}@endint main(int argc, const char * argv[]) { NSPointerArray *pa = [NSPointerArray weakObjectsPointerArray]; @autoreleasepool { TestClass *obj = TestClass.new; [pa addPointer:(__bridge void * _Nullable)(obj)]; // stores obj as a weak ref assert([pa pointerAtIndex:0] != nil); assert(!didDealloc); } // at this point the TestClass obj will be deallocated assert(didDealloc); assert([pa pointerAtIndex:0] == nil); // verify that the weak ref is null now return 0;}
If you run this you'll find that after adding the TestClass
object to the pointer array pa
, then releasing that object again, the pointer (which is internally a weak object ref) is now set to null as desired.
However, note that calling [pa compact]
at the end will not remove the nil pointer as I'd have expected.