4

I wrote a little convenience method on NSArray which works like PHP's list() function for "unpacking" an array into distinct objects:

- (void)unpackInto:(__strong id *)obj1, ...
{
    __strong id *idPtr;
    va_list args;
    va_start(args, obj1);

    idPtr = obj1;
    NSUInteger idx = 0;
    NSUInteger count = [self count];
    while (idPtr != NULL && idx < count) {
        *idPtr = [self objectAtIndex:idx];

        // Increment the args and idx count
        idx++;
        idPtr = va_arg(args, __strong id *);
    }
}

I originally had __autoreleasing id * but ran into a EXC_BAD_ACCESS issue when this method was called (twice actually, if it matters) on a thread with it's own autorelease pool to unpack the contents into temporary local stack vars. When the main thread came around and attempted to autorelease the contents (again), EXC_BAD_ACCESS was thrown.

Can anyone help me follow the logic with these bridging parameters in this case? I'm concerned that __strong will lead to the slightly less obvious but equally evil twin cousin: memory leak...

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
Hari Honor
  • 8,677
  • 8
  • 51
  • 54
  • 1
    Not quite sure what you are asking... NSArray defines the `-getObjects:range:` method, is that what you want? – Richard J. Ross III Feb 25 '12 at 15:46
  • 1
    "unpacking" is different. He wants the first parameter to be left pointing to the first value, the second parameter to be left pointing to the second value, etc. -getObjects:range: just leaves you with a C array. – Rob Napier Feb 25 '12 at 16:10
  • When you say "I originally had `__autoreleasing id *`, do you mean only in the signature, or also in your declaration of idPtr? Can you post the original code that crashed? – Rob Napier Feb 25 '12 at 16:43
  • Both. __autoreleasing was specified explicitly throughout. – Hari Honor Feb 25 '12 at 17:58

1 Answers1

2

I haven't seen your source code, but answer to most ARC problems can be solved if you think in terms of ownerships than retain/release/auto-release pools. Try to answer, who owns the array and who owns the unpacked pointers. If I understand you correctly, your calling method looks something like this

  NSArray *arr = [NSArray arrayWithObjects:@"a", @"b", @"c", @"d", nil];

  NSString *a, *b, *c, *d;
  [arr unpackInto:&a, &b, &c, &d, nil];

Is your array deallocated before you access the unpacked variables? Remember that __autoreleasing doesn't "retain" the values onto your variable argument pointers. So if your array is deallocated, your pointers become garbage. My guess, your EXC_BAD_ACCESS is because, your main array gets deallocated.

__strong shouldn't be used when you return by reference. It will not increase the retain count. There is no way to let ARC know that, these variables are to be released in the calling method. So ARC releases them after its scope. The only way to pass an allocated object to a calling method and let the calling method deallocate, is by returning it from a method that belongs to a init- family. When you return values across method boundaries, ARC uses method family (or the macros NS_RETURNS_RETAINED/NS_RETURNS_NON-RETAINED) to determine who "owns" the pointer.

You can use __strong for passing by reference if you pass a const pointer (non-writeback pointers) In fact, for const pointers without ownership qualifiers, __strong is implied.

More on this on LLVM documentation here http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.restrictions.pass_by_writeback

Mugunth
  • 14,461
  • 15
  • 66
  • 94
  • Thanks for the help @Mugunth. The objects are UITouch instances sent by the main run loop, stored in a strong property and then accessed by both threads on occasion. It seemed this method caused them to be autoreleased on the secondary thread's run loop which results in the main loop getting the error when it tries to do the same. Using instead: `UITouch *myLocalTouch = [touches objectAtIndex:0]` which implied "do nothing" wrt memory management, the problem disappears. Why is that? How do I tell a method, "do nothing" with these pointers? What exactly does __strong do in the above? – Hari Honor Mar 02 '12 at 11:40