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 为核心集合类(以及它们的可变版本)实现了这种功能: NSArray、NSDictionary、NSSet 和 NSOrderedSet。
任何遵守 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'.)
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的好处
EKEnumerable协议# import <EnumeratorKit.h>
@interface MyAwesomeCollection : NSObject <EKEnumerable>
...
@end+load和includeEKEnumerable+ (void)load
{
[self includeEKEnumerable];
}
-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的Enumerable和Enumerator功能有了很多了解。特别感谢