Сегодня я экспериментировал с блоками Objective-C, поэтому подумал, что буду умнее и добавлю в NSArray несколько методов сбора в функциональном стиле, которые я видел на других языках:
@interface NSArray (FunWithBlocks)
- (NSArray *)collect:(id (^)(id obj))block;
- (NSArray *)select:(BOOL (^)(id obj))block;
- (NSArray *)flattenedArray;
@end
Метод collect: принимает блок, который вызывается для каждого элемента в массиве и должен возвращать результаты некоторых операций с использованием этого элемента. Результатом является сбор всех этих результатов. (Если блок возвращает ноль, к результирующему набору ничего не добавляется.)
Метод select: вернет новый массив, содержащий только элементы из оригинала, которые при передаче в качестве аргумента блоку возвращали YES.
И, наконец, метод flateredArray выполняет итерации по элементам массива. Если элемент является массивом, он рекурсивно вызывает для него flattenArray и добавляет результаты в набор результатов. Если элемент не является массивом, он добавляет элемент в набор результатов. Набор результатов возвращается, когда все закончено.
Так что теперь, когда у меня была некоторая инфраструктура, мне понадобился тестовый пример. Я решил найти все файлы пакетов в системных каталогах приложений. Вот что я придумал:
NSArray *packagePaths = [[[NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory, NSAllDomainsMask, YES) collect:^(id path) { return (id)[[[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil] collect:^(id file) { return (id)[path stringByAppendingPathComponent:file]; }]; }] flattenedArray] select:^(id fullPath) { return [[NSWorkspace sharedWorkspace] isFilePackageAtPath:fullPath]; }];
Да - это все одна строка, и это ужасно. Я попробовал несколько подходов при добавлении новых строк и отступов, чтобы попытаться очистить его, но все равно кажется, что реальный алгоритм потерян во всем шуме. Однако я не знаю, является ли это проблемой с синтаксисом или моим относительным опытом использования функционального стиля.
Для сравнения я решил сделать это «по старинке» и просто использовать циклы:
NSMutableArray *packagePaths = [NSMutableArray new];
for (NSString *searchPath in NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory, NSAllDomainsMask, YES)) {
for (NSString *file in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:searchPath error:nil]) {
NSString *packagePath = [searchPath stringByAppendingPathComponent:file];
if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:packagePath]) {
[packagePaths addObject:packagePath];
}
}
}
ИМО эту версию было легче написать и она более читабельна для загрузки.
Полагаю, возможно, это был какой-то плохой пример, но мне кажется, что это законный способ использовать блоки. (Я ошибаюсь?) Я что-то упускаю из-за того, как написать или структурировать код Objective-C с блоками, которые очистили бы это и сделали бы его более понятным, чем (или даже столь же понятным, как) зацикленная версия?