Friday, April 9, 2010

Comparison of Objective-C Enumeration Techniques

Mike Ash:

If there are multiple contiguous object stores, NSFastEnumeration allows the collection to return interior pointers one after another, allowing for a quick loop implementation over each store, and requiring an Objective-C message only for getting the next interior pointer. For collections without contiguous storage, NSFastEnumeration allows the collection to copy objects out to temporary storage in bulk, reaping many of the same benefits. For collections where none of this works, NSFastEnumeration still allows a collection to efficiently return objects one by one.…Nice syntax, good performance, it’s a great combination.

Unfortunately, you can’t use fast enumeration if you support Mac OS X 10.4. Currently, I write all my loops using a foreach macro, which conditionally compiles to IMP-caching and NSEnumerator under 32 bit and for…in under 64-bit.

2 Comments RSS · Twitter

Do you have this code for your latest foreach posted anywhere? I used an earlier version of your macro for a few years, and really loved it! (Fortunately I haven't had to deal with Obj-C 1.0 code lately though, so I've been using the modern for…in.)

@Vincent Gable Here’s the current code:

#if __LP64__
#define foreacht(type, object, collection) \
    for (type object in collection)
#else
#define foreachGetEnumerator(c) \
    ([c respondsToSelector:@selector(objectEnumerator)] ? \
     [c objectEnumerator] : \
     c)
#define foreacht(type, object, collection) \
for (id foreachCollection = collection; \
     foreachCollection; \
     foreachCollection = nil ) \
    for (id foreachEnum = foreachGetEnumerator(foreachCollection); \
         foreachEnum; \
         foreachEnum = nil ) \
        for (IMP foreachNext = [foreachEnum methodForSelector:@selector(nextObject)]; \
             foreachNext; \
             foreachNext = NULL ) \
            for (type object = foreachNext(foreachEnum, @selector(nextObject)); \
                 object; \
                 object = foreachNext(foreachEnum, @selector(nextObject)) )
#endif
#define foreach(object, collection) foreacht(id, object, (collection))

In retrospect, perhaps I should have used OBJC_API_VERSION >= 2 instead of __LP64__.

Leave a Comment