Сегодня я экспериментировал с блоками Objective-C, поэтому я подумал, что буду умным и добавлю в NSArray несколько методов создания в стиле функционального стиля, которые я видел на других языках:
@interface NSArray (FunWithBlocks)
- (NSArray *)collect:(id (^)(id obj))block;
- (NSArray *)select:(BOOL (^)(id obj))block;
- (NSArray *)flattenedArray;
@end
Метод collect: принимает блок, который вызывается для каждого элемента массива, и ожидается, что он вернет результаты некоторой операции с использованием этого элемента. Результатом является сбор всех этих результатов. (Если блок возвращает nil, в результирующий набор ничего не добавляется.)
Метод select: возвращает новый массив только с элементами из оригинала, который, переданный в качестве аргумента блоку, возвращает ответ.
И, наконец, метод flattenedArray выполняет итерацию над элементами массива. Если элемент является массивом, он рекурсивно вызывает flattenedArray и добавляет результаты в результирующий набор. Если элемент не является массивом, он добавляет элемент в результирующий набор. Набор результатов возвращается, когда все будет завершено.
Итак, теперь, когда у меня была какая-то инфраструктура, мне нужен тестовый пример. Я решил найти все файлы пакетов в каталогах системных приложений. Вот что я придумал:
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];
}
}
}
IMO, эта версия была легче писать и более читаема для загрузки.
Я полагаю, это возможно, это был как-то плохой пример, но это похоже на законный способ использовать блоки для меня. (Я не прав?) Я что-то пропустил о том, как писать или структурировать код Objective-C с блоками, которые очистят его и станут понятнее, чем (или даже так же ясно, как) зацикленная версия?