EnumeratorKit 1.0.0

EnumeratorKit 1.0.0

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最后发布2015年3月

Adam Sharp维护。



  • 作者:
  • Adam Sharp

EnumeratorKit — Objective-C 中的 Ruby 风格枚举

EnumeratorKit 是一个集合枚举库,其设计灵感来源于 Ruby 中的 Enumerable 模块和 Enumerator 类。

它允许您以非常紧凑、表达力强的way与对象集合一起工作

#import <EnumeratorKit/EnumeratorKit.h>

NSArray *numbers = @[ @1, @2, @3 ];

// perform the block once for each element in the collection
[numbers each:^(id i){
    NSLog(@"%@", i);
}];

// return a new array with each element converted to a string
[numbers map:^(id i){
    return [i stringValue];
}];

此外,这些操作可以连锁在一起,形成更高级别的操作

NSDictionary *examples = @{ @"Hello": @"world", @"foo": @"BAR" };

[[[examples sortBy:^(id pair){
    // sort entries by their keys, case insensitive
    return [pair[0] lowercaseString];
}] map:^(id pair){
    // combine each key-value pair into a new string
    return [NSString stringWithFormat:@"%@ %@", pair[0], pair[1]];
}] select:^(id pair){
    return [pair[1] hasSuffix:@"orld"];
}];
// => @[@"Hello world"];

EnumeratorKit 为核心集合类(以及它们的可变版本)实现了这种功能: NSArrayNSDictionaryNSSetNSOrderedSet

任何遵守 NSFastEnumeration 的集合都可以方便地使用 ek_enumerate 函数包装

[ek_enumerate(@[@1, @2, @3]) map:^(NSNumber *i) {
    return @(i.integerValue * 2);
}];
// => @[@2, @4, @6]

EnumeratorKit 还提供了 EKEnumerator 类,它相比 NSEnumerator 有许多优点,例如

  • 能够在不消耗枚举的情况下查看下一个元素的能力
  • 实现了整个 EKEnumerable API
  • 无限集合上的懒枚举
// you may have seen this in Ruby before
EKEnumerator *fib = [EKEnumerator new:^(id<EKYielder> yielder){
    int a = 1, b = 1;
    while (1) { // infinite loop (!)
        [yielder yield:@(a)];
        NSUInteger next = a + b;
        a = b; b = next;
    }
}];
[[fib take:10] asArray]; // => @[ @1, @1, @2, @3, @5, @8, @13, @21, @34, @55 ]

开始使用

安装

EnumeratorKit 通过 CocoaPods 可用。将其添加到您的 Podfile 中。

pod 'EnumeratorKit', '~> 0.1.1'

(不要忘记运行 pod install.) 然后导入头文件

#import <EnumeratorKit/EnumeratorKit.h>

现在您可以继续使用它了。

(注意:如果您只想使用 EKFiber,而不使用 EKEnumerable 的其余部分,您可以使用此子规范: pod 'EnumeratorKit/EKFiber'.)

要求

  • iOS 5.0+
  • 支持 Objective-C 集合字面的基本 SDK

它是如何工作的

EKEnumerable 类定义了一个基于一个操作的方法的 API

- (instancetype)each:(void (^)(id obj))block;

不同的集合类实现了自己的 -each: 版本,以便定义其元素遍历的顺序。例如,在 NSArray 上,-each: 被定义为依次对每个项执行一次。对于 NSDictionary-each: 构建一个键值对的两个元素数组 @[key, value] 并将其传递给块,每次传递一个条目。

EnumeratorKit会使用Objective-C运行时将所有在EKEnumerable中定义的方法“混合”到另一个类中(类似于Ruby模块)。这类似于使用Objective-C类别向现有类添加方法,但是完全在运行时完成。(还有一个附加优点,如果您继承自EKEnumerable类,可以覆盖EKEnumerable提供的任何方法。但是,类别方法会破坏多态性。)

通过用-each:定义API,任何类都可以通过实现该方法和混合EKEnumerable来获得该功能。

可用方法

Kiwi测试提供很多有用的示例。(如果您想了解更多,我还建议查看Ruby的Enumerable文档。)以下是支持的操作的快速浏览:

  • -each —— 对集合中的每个项目执行块一次
  • -eachWithIndex —— 与-each类似,但是在块中将当前索引作为第二个参数传递
  • -asArray —— 获取任何枚举的数组表示
  • -take —— 从枚举的开始处获取指定数量的元素
  • -map —— 对集合中的每个项目应用块,返回转换后的值的新集合
  • -select —— 创建一个新枚举,包含块返回YES的所有元素
  • -find —— 返回第一个块返回YES的元素,如果没有找到匹配元素,则为nil
  • -any —— 检查集合中的元素是否通过块
  • -all —— 检查集合中的所有元素是否通过块
  • -sort —— 返回一个排序数组(集合中的项目必须响应compare:
  • -sortWith —— 与-sort类似,但允许您指定一个NSComparator
  • -sortBy —— 使用将块应用于每个元素的结果作为排序接收者的排序键进行排序
  • -reduce —— 遍历枚举,在每一步中对块进行评估,并累积新值(例如,将数字数组“减少”为一个表示总和的单个数字)

使自己的集合类成为枚举类型

您非常容易在您自己的集合类中获得整个EKEnumerable API的好处

1. 在类的公共接口中采用EKEnumerable协议

# import <EnumeratorKit.h>
@interface MyAwesomeCollection : NSObject <EKEnumerable>
...
@end

2. 在实现中,覆盖+loadincludeEKEnumerable

+ (void)load
{
    [self includeEKEnumerable];
}

3. 实现-each:,和-initWithEnumerable:

@implementation MyAwesomeCollection
.
.
.
- (instancetype)initWithEnumerable:(id<EKEnumerable>)enumerable
{
    // traverse the enumerable, adding each item to your collection
}

- (instancetype)each:(void (^)(id))block
{
    // hypothetical enumeration code
    for (int i; i < self.length; i++) {
        // call the block, passing in each element
        block(self[i]);
    }

    // make sure you return self, to enable enumerator chaining
    return self;
}
.
.
.
@end

贡献力量

我建议在花费大量时间开发新功能之前先打开一个问题。然而,如果您的更改相对独立,通常更容易以拉取请求的形式进行评估。

致谢

实现这个项目的第一个版本让我对Objective-C以及Ruby的EnumerableEnumerator功能有了很多了解。特别感谢