What Drove Me to Finally Write a Map Method
I try to add category methods sparingly, on the principle that creating my own personal dialect of Cocoa is a bad idea. (That’s not to say I never do. Here are some.)
Much of the time I can get by without a map method by using either valueForKeyPath: or filteredArrayUsingPredicate:.
But today I ran across one that required both methods.
I have an array of notes (for Vesper’s timeline). Each note has a thumbnailID property — which is nil when there’s no thumbnail.
I wanted an array of non-nil thumbnailIDs.
I could get all the thumbnailIDs, including nils, which turn into NSNulls, with valueForKeyPath:.
NSArray *thumbnailIDs = [notes valueForKeyPath:VSThumbnailIDKey];
And then I could get non-nil thumbnailIDs:
NSArray *thumbnailIDsMinusNulls = [thumbnailIDs filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != nil"]];
And that’s not terrible. But I looked around for a better way and didn’t find anything. So I finally broke down and wrote a map method.
So now the code looks like this:
NSArray *thumbnailIDsMinusNulls = [objects qs_map:^id(id obj) {
return ((VSTimelineNote *)obj).thumbnailID;
}];
If thumbnailID is nil, the block returns nil and it doesn’t get added to the array.
The map function (in an NSArray category) looks like this:
typedef id (^QSMapBlock)(id obj);
- (NSArray *)qs_map:(QSMapBlock)mapBlock {
NSMutableArray *mappedArray = [NSMutableArray new];
for (id oneObject in self) {
id objectToAdd = mapBlock(oneObject);
if (objectToAdd) {
[mappedArray addObject:objectToAdd];
}
}
return [mappedArray copy];
}
It’s surprising to me that there isn’t a built-in map method for NSArray. I may be the last Cocoa programmer to write my own.