【发布时间】:2009-09-22 19:55:36
【问题描述】:
今天我正在尝试使用 Objective-C 的块,所以我想我会很聪明,并在 NSArray 中添加一些我在其他语言中见过的函数式集合方法:
@interface NSArray (FunWithBlocks)
- (NSArray *)collect:(id (^)(id obj))block;
- (NSArray *)select:(BOOL (^)(id obj))block;
- (NSArray *)flattenedArray;
@end
collect: 方法采用一个块,该块为数组中的每个项目调用,并期望返回使用该项目的某些操作的结果。结果是所有这些结果的集合。 (如果块返回 nil,则不会向结果集中添加任何内容。)
select: 方法将返回一个新数组,其中仅包含原始项目中的项目,当作为参数传递给块时,块返回 YES。
最后,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 代码的内容,这些块可以清理它并使其比循环版本更清晰(甚至和循环版本一样清晰)?
【问题讨论】: