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) {
</br>
return ((VSTimelineNote \*)obj).thumbnailID;
</br>
}];
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 {
</br>
</br>
NSMutableArray \*mappedArray = [NSMutableArray new];
</br>
</br>
for (id oneObject in self) {
</br>
</br>
id objectToAdd = mapBlock(oneObject);
</br>
if (objectToAdd) {
</br>
[mappedArray addObject:objectToAdd];
</br>
}
</br>
}
</br>
</br>
return [mappedArray copy];
</br>
}
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.