2

Given the following code:

    NSMutableArray *a = [NSMutableArray array];
    NSMutableArray *b = [NSMutableArray array];

    [a addObject:b];
    [b addObject:a];

What are the options to make the array objects deallocate when I set a and b to NIL?

Ive tried few things (Like weak references) but it doesn't seem to work.. (Probably because I don't understand enough - new to objective c ).

would love to get some assistance.

thank you

Rouki
  • 2,239
  • 1
  • 24
  • 41
  • 1
    What are you trying to do? Why are they both containing each other? Seems a bit contrived to me. – David Rönnqvist Jul 17 '13 at 18:26
  • It is a pretty contrived example, but in general I think weak proxies are a good solution to preventing retain cycles, especially when you want to store weak references in arrays without having to un-box them all the time (See my answer). You can also add some code to automatically clean up the array and remove items that are gone away and therefore auto-zeroed. – jhabbott Jul 18 '13 at 11:23

4 Answers4

0

It's explained here: Non-retaining array for delegates.

You can use

+ (NSValue *)valueWithNonretainedObject:(id)anObject

And put the NSValue in the array.

Or do that:

NSMutableArray* NICreateNonRetainingMutableArray(void) {
  return (NSMutableArray *)CFArrayCreateMutable(nil, 0, nil);
}

NSMutableDictionary* NICreateNonRetainingMutableDictionary(void) {
  return (NSMutableDictionary *)CFDictionaryCreateMutable(nil, 0, nil, nil);
}

NSMutableSet* NICreateNonRetainingMutableSet(void) {
  return (NSMutableSet *)CFSetCreateMutable(nil, 0, nil);
}
Community
  • 1
  • 1
MatLecu
  • 953
  • 8
  • 14
0

you can make an entire array not retain its elements with: CFArrayCreate()

this can be problematic in ARC if you no longer use the elements then iterate through the array later.

Grady Player
  • 14,399
  • 2
  • 48
  • 76
0

One solution to this kind of thing is to wrap your objects in a weak proxy object. Here is an example implementation of such an object:

https://github.com/j-h-a/jalib-core/blob/master/JALibCore/Helpers/JAWeakProxy.h

https://github.com/j-h-a/jalib-core/blob/master/JALibCore/Helpers/JAWeakProxy.m

Then you can do this:

NSMutableArray* a = [NSMutableArray array];
NSMutableArray* b = [NSMutableArray array];
[a addObject:[JAWeakProxy weakProxyWithTarget:b]];
[b addObject:[JAWeakProxy weakProxyWithTarget:a]];

Now both a and b are weakly referenced within the array. The good thing about using weak proxy objects is that you don't need to 'unbox' the real object inside them - you can just send messages (call methods) directly on the weak proxy object as if it were the target and it will pass the message along. For example:

[a[0] addObject:@(0)];

Notice how a[0] actually returns the weak proxy object holding b as its target, but I can sill send addObject directly to this weak proxy representing b (which is an NSMutableArray) and the implementation of the weak proxy will ensure that the message is forwarded to b.

However, you do lose some compile-time type-checking, so this technique is best used to help with the internal implementation of some class, which will have well-typed methods to access and enumerate the contents.

When I use such things I usually put in some auto-clean-up code into the array enumerators. That is I hide the arrays inside a utility class and provide block-based enumeration methods and I also keep a toRemove array. When iterating I skip any objects that the target has auto-zeroed to nil and add them to the toRemove array (the weak proxy object still exists even though its target is gone), then afterwards I iterate through the toRemove array and remove the proxy objects. You can also check if the target is nil and add it to the toRemove array in any accessor helpers.

jhabbott
  • 18,461
  • 9
  • 58
  • 95
0

I'm not sure how you tried to add weak references to an array, but if it was something like this:

NSMutableArray *myArray = [NSMutableArray new]
__weak id weakObject = blah;
[myArray addObject:weakObject]

Then the fact that weakObject is declared weak makes no difference. It only makes the local reference to your object from the stack weak. In your situation, the array needs to hold a weak reference to the object, and NSMutableArray always holds strong references to its members.

There are several ways of doing this. CFArray allows you to specify how it should retain its members when you create it. Or you could 'box' the reference inside an NSValue, which although retained itself by the array, does not retain its contents.

If you're targeting Mac or iOS 6.0+, the best solution is to use a weak NSPointerArray (created using [NSPointerArray weakObjectsPointerArray]).

This is better than using CFArray or an NSValue inside a normal NSMutableArray because when the referenced object is deallocated, the array element will be automatically set to nil.

Chris Devereux
  • 5,453
  • 1
  • 26
  • 32