使用Objective-C块 [英] Using Objective-C Blocks

查看:146
本文介绍了使用Objective-C块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天我正在实验Objective-C的块,所以我想我会聪明,并添加到NSArray几个功能样式收集方法,我曾在其他语言看到:

Today I was experimenting with Objective-C's blocks so I thought I'd be clever and add to NSArray a few functional-style collection methods that I've seen in other languages:

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

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

The collect: method takes a block which is called for each item in the array and expected to return the results of some operation using that item. The result is the collection of all of those results. (If the block returns nil, nothing is added to the result set.)

select:方法将返回一个只包含原始项目的新数组,作为参数传递给块,块返回YES。

The select: method will return a new array with only the items from the original that, when passed as an argument to the block, the block returned YES.

最后,flattenedArray方法遍历数组的项。如果一个项目是一个数组,它会递归调用flattenedArray,并将结果添加到结果集。如果项目不是数组,它会将项目添加到结果集。当一切完成后,返回结果集。

And finally, the flattenedArray method iterates over the array's items. If an item is an array, it recursively calls flattenedArray on it and adds the results to the result set. If the item isn't an array, it adds the item to the result set. The result set is returned when everything is finished.

现在我有一些基础设施,我需要一个测试用例。我决定在系统的应用程序目录中找到所有的包文件。这是我想出来的:

So now that I had some infrastructure, I needed a test case. I decided to find all package files in the system's application directories. This is what I came up with:

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]; }];

是的 - 这一切都是一行,可怕。我尝试了几种方法添加换行和缩进来尝试清理它,但它仍然感觉像实际的算法丢失在所有的噪音。我不知道它是一个语法的事情,或者我的亲戚使用一个功能风格的问题,虽然。

Yep - that's all one line and it's horrid. I tried a few approaches at adding newlines and indentation to try to clean it up, but it still feels like the actual algorithm is lost in all the noise. I don't know if it's just a syntax thing or my relative in-experience with using a functional style that's the problem, though.

为了比较,我决定做它旧的方式,只使用循环:

For comparison, I decided to do it "the old fashioned way" and just use loops:

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这个版本更容易写和更可读的启动。

IMO this version was easier to write and is more readable to boot.

我想这可能是一个坏的例子,但它似乎是一个合法的方式使用块。 (我错了吗?)我缺少一些关于如何编写或结构的Objective-C代码块,它会清理这一点,使它比循环版本更清晰(甚至清楚)。

I suppose it's possible this was somehow a bad example, but it seems like a legitimate way to use blocks to me. (Am I wrong?) Am I missing something about how to write or structure Objective-C code with blocks that would clean this up and make it clearer than (or even just as clear as) the looped version?

推荐答案

使用换行符并在多行之间拆分您的通话。

Use newlines and break up your call across multiple lines.

所有的苹果的API是一个方法或函数应该只采取一个块参数,该参数应该总是最后一个参数。

The standard pattern used across all of Apple's APIs is that a method or function should only take one block argument and that argument should always be the last argument.

你已经做了。

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

Now, when writing the code that uses said API, do something like:

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

您的收集/选择/过滤/ flatten / map /任何作为一个单独的步骤的每一步。这将不会比链接的方法调用更快/更慢。

I.e. do each step of your collect/select/filter/flatten/map/whatever as a separate step. This will be no faster/slower than chained method calls.

如果你需要在块的块中嵌套块,那么完全缩进:

If you do need to nest blocks in side of blocks, then do so with full indention:

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

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

Just like nested if statements or the like. When it gets too complex, refactor it into functions or methods, as needed.

这篇关于使用Objective-C块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆