1

How can I implement a class/object that has a reference to a bunch of non-retained id objects?

I want something similar to what UIControl/NSControl has: addTarget:(id)target action:(SEL)action ...; (in my case, though, I don't need the UIControlEvents part). I want to use this target/action pattern (and preferably stay away from the delegate pattern) but for that I need to make sure the targets added to my object are not retained or retain cycles might happen.

I think implementing my own array using malloc/free to make sure targets are not retained would be one solution, but all this hassle smells like there is already a solution implemented somewhere. Is there?

jscs
  • 63,694
  • 13
  • 151
  • 195
nacho4d
  • 43,720
  • 45
  • 157
  • 240

2 Answers2

4

On OS X you can create an NSPointerArray that will keep weak references to its objects with +[NSPointerArray weakObjectsPointerArray], or (if you want a dictionary) an NSMapTable which allows either or both of the keys and values to be held weakly.

Neither of those are available currently on iOS, but Core Foundation is. On either OS X or iOS you can use CFArray or CFDictionary, passing NULL for the callbacks to make the collection do no memory management of its contained objects. Be warned that if you try to use these as if they were their toll-free bridged Cocoa counterparts, the collection will not honor your non-retaining/non-copying desire. You'll have to use the CF functions to interact with them (or whip up a wrapper class).

You can also wrap your objects in NSValues, using valueWithNonretainedObject:, and put those into a Cocoa collection (NSDictionary/NSarray). The collection will own the value, but the value will not own its object.

jscs
  • 63,694
  • 13
  • 151
  • 195
  • I would give more points but only 1 click in the ▲ is permitted. This worked very good! – nacho4d Aug 13 '12 at 06:21
  • Since I am in iOS the `NSPointerArray` was discarded (I guess this is one the classes that were/are not ported to iOS yet). I thought of `CFArray` too but as you pointed out toll-free bridge calls could become a bit cumbersome so I used `[NSValue valueWithNonretainedObject:]` and it works like a charm :) – nacho4d Aug 14 '12 at 06:44
1

You could create a CFArrayRef, specifying callbacks which do not perform ref count operations (or just 0 for the callbacks if you are feeling very lazy):

CFAllocatorRef allocator = 0;
const void **values = ...;
CFIndex numValues = ...;
const CFArrayCallBacks* const callBacks = 0;

CFArrayRef arr = CFArrayCreate(allocator, values, numValues, callBacks);
justin
  • 104,054
  • 14
  • 179
  • 226