GNU Objective-C provides support for the fast enumeration syntax:
id array = ...;
id object;
for (object in array)
{
/* Do something with 'object' */
}
array needs to be an Objective-C object (usually a collection object, for example an array, a dictionary or a set) which implements the ‘Fast Enumeration Protocol’ (see below). If you are using a Foundation library such as GNUstep Base or Apple Cocoa Foundation, all collection objects in the library implement this protocol and can be used in this way.
The code above would iterate over all objects in array. For each of them, it assigns it to object, then executes the Do something with 'object' statements.
Here is a fully worked-out example using a Foundation library (which provides the implementation of NSArray, NSString and NSLog):
NSArray *array = [NSArray arrayWithObjects: @"1", @"2", @"3", nil];
NSString *object;
for (object in array)
NSLog (@"Iterating over %@", object);
A c99-like declaration syntax is also allowed:
id array = ...;
for (id object in array)
{
/* Do something with 'object' */
}
this is completely equivalent to:
id array = ...;
{
id object;
for (object in array)
{
/* Do something with 'object' */
}
}
but can save some typing.
Note that the option -std=c99 is not required to allow this syntax in Objective-C.
Here is a more technical description with the gory details. Consider the code
for (``object expression`` in ``collection expression``)
{
``statements``
}
here is what happens when you run it:
If you want your own collection object to be usable with fast enumeration, you need to have it implement the method
where NSFastEnumerationState must be defined in your code as follows:
typedef struct
{
unsigned long state;
id *itemsPtr;
unsigned long *mutationsPtr;
unsigned long extra[5];
} NSFastEnumerationState;
If no NSFastEnumerationState is defined in your code, the compiler will automatically replace NSFastEnumerationState * with struct __objcFastEnumerationState *, where that type is silently defined by the compiler in an identical way. This can be confusing and we recommend that you define NSFastEnumerationState (as shown above) instead.
The method is called repeatedly during a fast enumeration to retrieve batches of objects. Each invocation of the method should retrieve the next batch of objects.
The return value of the method is the number of objects in the current batch; this should not exceed len, which is the maximum size of a batch as requested by the caller. The batch itself is returned in the itemsPtr field of the NSFastEnumerationState struct.
To help with returning the objects, the objects array is a C array preallocated by the caller (on the stack) of size len. In many cases you can put the objects you want to return in that objects array, then do itemsPtr = objects. But you don’t have to; if your collection already has the objects to return in some form of C array, it could return them from there instead.
The state and extra fields of the NSFastEnumerationState structure allows your collection object to keep track of the state of the enumeration. In a simple array implementation, state may keep track of the index of the last object that was returned, and extra may be unused.
The mutationsPtr field of the NSFastEnumerationState is used to keep track of mutations. It should point to a number; before working on each object, the fast enumeration loop will check that this number has not changed. If it has, a mutation has happened and the fast enumeration will abort. So, mutationsPtr could be set to point to some sort of version number of your collection, which is increased by one every time there is a change (for example when an object is added or removed). Or, if you are content with less strict mutation checks, it could point to the number of objects in your collection or some other value that can be checked to perform an approximate check that the collection has not been mutated.
Finally, note how we declared the len argument and the return value to be of type unsigned long. They could also be declared to be of type unsigned int and everything would still work.