Implementing NSFastEnumeration for a custom class requires us to implement one method which will be called when we use for (var in coll) // { .. } form. Let's say we have a class DLList which is backed by an array as its main data source. For iterating elements in the DLList object, we can do as follows.

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id  _Nullable __unsafe_unretained [])buffer count:(NSUInteger)len {
    if (state->state == [self count]) return 0;
    __unsafe_unretained id const *arr = &_array;  // (1)
    state->itemsPtr = (__typeof__(state->itemsPtr))arr;  // (2)
    state->mutationsPtr = &state->extra[0];  // (3)
    state->state = [self count];
    return state->state;
}

Here state->itemsPtr requires a pointer to any object of type id. We use _array and pointer to the _array can be obtained by getting the address, &_array. But holding a reference to the variable will change its retain count, which we do not want. So in statement marked (1) we use __unsafe_unretained id const * as the type. We don't check for mutation here (3) as the collection is not being mutated during enumeration.

The Clang documentation on Objective-C Automatic Reference Counting (ARC) discusses the semantics of casts under ARC.

A program is ill-formed if an expression of type T* is converted, explicitly or implicitly, to the type U*, where T and U have different ownership qualification, unless:

  • T is qualified with __strong, __autoreleasing, or __unsafe_unretained, and U is qualified with both const and __unsafe_unretained; or

In statement marked (2), we then typecast it to the type of state->itemsPtr which is same as __unsafe_unretained id * removing the const, which works because the ownership is the same.

The DLList class snippet is given below.

@implementation DLList {
    NSMutableArray *_array;
}

- (NSUInteger)count {
    return [_array count];
}

// ..

Now we can use fast enumeration like:

DLList *list = [[DLList alloc] initWithArray:@[@(1), @(2), @(3)]];
NSNumber *num = nil;
for (num in list) {  // fast enumeration which will call the protocol method
    NSLog(@"Elems: %@", num);
}