3

How can I safely store a couple object instances in NSFastEnumerationState's extra array?

I want these items to be retained while the loop is running, then released when the loop is complete.

- (NSUInteger)countByEnumeratingWithState: (NSFastEnumerationState *)state
                                  objects: (__unsafe_unretained id *)stackbuf
                                    count: (NSUInteger)len {
    unsigned long days = 0;
    id current = nil;
    id components = nil;
    if (state->state == 0)
    {
        current = [NSCalendar currentCalendar];
        state->mutationsPtr = &state->extra[0];
        components = [current components: NSDayCalendarUnit fromDate: _startDate toDate: _endDate options: 0];
        days = [components day];
        state->extra[0] = days;
        state->extra[1] = (uintptr_t)(__bridge void *)current;
        state->extra[2] = (uintptr_t)(__bridge void *)components;
    } else {
        days = state->extra[0];
        current = (__bridge NSCalendar *)(void *)(state->extra[1]);
        components = (__bridge NSDateComponents *)(void *)(state->extra[2]);
    }
    NSUInteger count = 0;
    if (state->state <= days) {
        state->itemsPtr = stackbuf;
        while ( (state->state <= days) && (count < len) ) {
            [components setDay: state->state];
            stackbuf[count] = [current dateByAddingComponents: components toDate: _startDate options: 0];
            state->state++;
            count++;
        }
    }
    return count;
}

Here's the definition of NSFastEnumerationState, from Apple's headers:

typedef struct {
    unsigned long state;
    id __unsafe_unretained *itemsPtr;
    unsigned long *mutationsPtr;
    unsigned long extra[5];
} NSFastEnumerationState;
Steven Fisher
  • 44,462
  • 20
  • 138
  • 192
  • I'ld be suprised since those elemtents are longs by default. typecasting them towards a pointer seems to be rather adventures already - hoping that any objects assigned to them would be retained seems impossible without further mechanics. Interesting question though, hence a +1 :D – Till Oct 12 '12 at 20:44
  • Yes, my AR conversion (done yesterday) was naive, and I'm assuming I'll have to add my own mechanics. I'm hoping someone understands this better than I. :) – Steven Fisher Oct 12 '12 at 21:05
  • I've added the definition of `NSFastEnumerationState`. – Steven Fisher Oct 12 '12 at 21:06
  • You could do `state->extra[1] = (uintptr_t)(__bridge_retained __strong void *)current;`. But that's considered poor form as per http://clang.llvm.org/docs/AutomaticReferenceCounting.html#objects.operands.casts . In general, though, this is near on impossible to do with ARC, unfortunately. – mattjgalloway Oct 12 '12 at 21:54
  • I'm not too concerned with it being bad form, as this is really primitive. As long as it's possible to clean up after the loop is finished -- which I don't think it is. :) – Steven Fisher Oct 12 '12 at 23:34

1 Answers1

1

Steven,

Why are you trying to use a C-language structure to hold these items rather than just make them private ivars in the class for which you are building an enumerator? Make them ivars and the problem just doesn't exist.

Andrew

adonoho
  • 4,339
  • 1
  • 18
  • 22