Monopol
Monopol

Reputation: 181

Implementing NSFastEnumerator: EXC_BAD_ACCESS when iterating with for…in

I have a data structure that I wanted to enumerate. I tried to implement my object's NSFastEnumerator as follows:

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state 
                                  objects:(__unsafe_unretained id [])buffer 
                                    count:(NSUInteger)len {

    NSUInteger c = 0;
    while (c < len) {
        id obj = [self objectAtIndex:state->state];
        if (obj == nil) break;
        buffer[c] = obj;
        c++;
        state->state++;
    }
    state->itemsPtr = buffer;
    state->mutationsPtr = nil;
    return c;
}

If I use objectAtIndex directly, my object works properly. I get a nil when the index doesn't exist. But when I then use the for loop:

for (Pin *pin in coll) { ... }

the code runs through the above function fine and fills in state with what appears to be valid values and returns the number of objects, then I get an EXC_BAD_ACCESS failure at the for statement itself.

What am I doing wrong in this implementation?

Upvotes: 4

Views: 413

Answers (3)

matehat
matehat

Reputation: 5374

I just had a similar issues, and after looking more closely into Apple's FastEnumerationSample, this part (that I had overlooked) jumped at me:

// We are not tracking mutations, so we'll set state->mutationsPtr to point into one of our extra values,
// since these values are not otherwise used by the protocol.
// If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated.
// state->mutationsPtr MUST NOT be NULL.
state->mutationsPtr = &state->extra[0];

The important part being: state->mutationsPtr MUST NOT be NULL. I just used the example line provided and it worked like a charm!

Upvotes: 2

Siby
Siby

Reputation: 318

Instead of:

id obj = [self objectAtIndex:state->state];

use

__unsafe_unretained id  = [self objectAtIndex:state->state];

Upvotes: 0

jtbandes
jtbandes

Reputation: 118671

I'm assuming you're using ARC. The problem may be that the buffer is an array of __unsafe_unretained objects, so ARC might be over-releasing them. But what does your objectAtIndex: method look like? This shouldn't be a problem if you are returning objects that are guaranteed to be alive at least as long as your object itself.

Upvotes: 1

Related Questions