objective-c - 使用 Objective-C block

标签 objective-c coding-style

今天我正在试验 Objective-C 的 block ,所以我想我应该聪明一点,向 NSArray 添加一些我在其他语言中见过的函数式集合方法:

@interface NSArray (FunWithBlocks)
- (NSArray *)collect:(id (^)(id obj))block;
- (NSArray *)select:(BOOL (^)(id obj))block;
- (NSArray *)flattenedArray;
@end

collect: 方法采用一个 block ,该 block 为数组中的每个项目调用,并期望返回使用该项目的某些操作的结果。结果是所有这些结果的集合。 (如果该 block 返回 nil,则不会向结果集中添加任何内容。)

select: 方法将返回一个新数组,其中仅包含原始数组中的项目,当作为参数传递给 block 时, block 返回 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 这个版本更容易编写并且启动时更具可读性。

我想这可能是一个不好的例子,但对我来说这似乎是使用 block 的合法方式。 (我错了吗?)我是否遗漏了一些关于如何使用 block 来编写或构建 Objective-C 代码的信息,这些 block 可以清理它并使其比循环版本更清晰(甚至一样清晰)?

最佳答案

使用换行符并将您的通话分成多行。

Apple 的所有 API 使用的标准模式是一个方法或函数应该只接受一个 block 参数,并且该参数应该始终是最后一个参数。

你做了什么。好。

现在,在编写使用所述 API 的代码时,执行如下操作:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory, NSAllDomainsMask, YES);
paths = [paths collect: ^(id path) {
    ...
}];
paths = [paths collect: ^(id path) {
    ...
}];
paths = [paths select: ^(id path) {
    ...
}];

即将收集/选择/过滤/展平/ map /任何其他步骤作为一个单独的步骤进行。这不会比链式方法调用更快/更慢。

如果您确实需要在 block 的边上嵌套 block ,则使用完整缩进:

paths = [paths collect: ^(id path) {
    ...
    [someArray select:^(id path) {
        ...
    }];
}];

就像嵌套的 if 语句之类的。当它变得太复杂时,根据需要将其重构为函数或方法。

关于objective-c - 使用 Objective-C block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1462245/

相关文章:

iphone - 如何手动发送 UIKeyboard 通知

c - 如何用纯C优雅地实现不同类型版本的一系列功能?

java - 反射性能 : quality byte code in JVM

coding-style - 如何自定义/设置UIPopoverController的样式

c++ - 为什么在 C++ 类中的成员变量上使用前缀

ios - NSPredicate 用于仅查找第一个匹配项

iphone - 如何提示用户在 Alert View 中输入文本

iphone - 创建UITableView后调用哪个协议(protocol)方法

ios - 如果日期列在开始日期和结束日期之间,则选择行 FMDB 请求

coding-style - Python求和式问题