Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatic Reference Counting: Error with fast enumeration

While updating the code below to use Automatic Reference Counting for iOS 5, an error is occurring when the "state->itemPtr" is assigned the buffer when trying to perform Fast Enumeration so that the implementing class can be iterated with the "foreach" loop. The error I am getting is "Assigning '__autoreleasing id *' to '__unsafe_unretained id*' changes retain/release properties of pointer". See the line of code with the comment.

/*
 * @see http://cocoawithlove.com/2008/05/implementing-countbyenumeratingwithstat.html
 * @see http://www.mikeash.com/pyblog/friday-qa-2010-04-16-implementing-fast-enumeration.html
 */
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state objects: (id *)buffer count: (NSUInteger)bufferSize {
    NSUInteger arrayIndex = (NSUInteger)state->state;
    NSUInteger arraySize = [_tuples count];
    NSUInteger bufferIndex = 0;

    while ((arrayIndex < arraySize) && (bufferIndex < bufferSize)) {
        buffer[bufferIndex] = [_tuples objectAtIndex: arrayIndex];
        arrayIndex++;
        bufferIndex++;
    }

    state->state = (unsigned long)arrayIndex;
    state->itemsPtr = buffer; // Assigning '__autoreleasing id *' to '__unsafe_unretained id*' changes retain/release properties of pointer
    state->mutationsPtr = (unsigned long *)self;

    return bufferIndex;
}

The _tuples variable in this example is an instance variable of type NSMutableArray.

How do I resolve this error?

like image 903
Ziminji Avatar asked Oct 19 '11 00:10

Ziminji


2 Answers

You need to change buffer into __unsafe_unretained:

- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state
                                   objects: (id __unsafe_unretained *)buffer
                                     count: (NSUInteger)bufferSize

source

Edit: easy way to get rid of the error in mutationPtr:

state->mutationsPtr = &state->extra[0];
like image 161
Dani Avatar answered Nov 06 '22 06:11

Dani


Ziminji,

I had the same problem, which is how I came across this question.

I solved it by keeping the definition of the objects parameter as is (e.g., keeping it as id *) and instead doing a double cast utilizing a void pointer.

So, while this generated errors for me:

state->itemsPtr = (__unsafe_unretained id *)buffer  // Error

This worked beautifully:

state->itemsPtr = (__unsafe_unretained id *)(void *)buffer  // No error

Disclaimer: I'm not an ARC expert and I can't guarantee you that this won't cause problems with reference counts. However, it appears to work correctly in my testing, and it definitely compiles without warnings.

BTW, I came across this two-part blog entry which covers Fast Enumeration in a nice amount of depth:

  • Fast Enumeration, Part 1
  • Fast Enumeration, Part 2

and also this blog entry on __unsafe_unretained:

  • Unsafe at Any Speed
like image 34
Todd Lehman Avatar answered Nov 06 '22 07:11

Todd Lehman