MogKit 是一个工具包,提供对集合和任何一系列值(如信号、通道等)的测试齐全且易于组合的转换。这些转换不依赖于基础值或数据结构,使得它们高度可重用。
与类似转换框架相比,MogKit 使用组合而不是链式调用进行操作,这意味着值仅迭代一次,而不是每次步骤迭代一次。
有一些情况下使用 MogKit 可能是有意义的。以下是一个示例。
当您只想将一些数据(例如数组)转换成新数组时。
NSArray *array = @[@1, @2, @3];
NSArray *result = [array mog_transform:MOGMap(^id(NSNumber *number) {
return @(number.intValue + 100);
});
// result is now @[@101, @102, @103]
或者处理一些数字并输出为字符串
NSArray *array = @[@1, @2, @3];
NSString *result = MOGTransform(array, MOGStringConcatReducer(@", "), MOGCompose(MOGMap(^id(NSNumber *val) {
return @(val.intValue + 10);
}), MOGMap(^id(NSNumber *val) {
return val.stringValue;
})));
// result = "11, 12, 13"
它也可以用于任何 NSObject
id object = @10;
NSArray *expected = @[@(-10), @0, @10];
NSArray *result = [object mog_transform:MOGFlatMap(^id(NSNumber *number) {
return @[@(-number.intValue), @0, number];
}) reducer:MOGArrayReducer()];
// result = @[@(-10), @0, @10]
另一种情况是,当您有一些数据结构并想为它添加一个转换方法时,例如扩展 NSArray
并为其添加一个 filter
方法,您只需这样做:
@implementation NSArray (Filterable)
- (NSArray *)filter:(MOGPredicate)predicate
{
return [self mog_transform:MOGFilter(predicate)];
}
@end
假设您想向 NSArray
添加一个 trim:
方法,该方法返回一个从开始和结束处去除 trimSize
个元素的新数组。
- (NSArray *)trim:(NSUInteger)trimSize
{
return [self mog_transform:MOGCompose(MOGDrop(trimSize), MOGTake(self.count - 2 * trimSize))];
}
使用 MogKit 并不仅仅是针对实现 NSFastEnumeration
的容器。您可以轻松地为任何想要转换值集的地方添加组合转换。以下是在 RACStream
(来自 ReactiveCocoa)上添加 -mog_transform:
方法的一个示例,以便对所有流上的值应用传入的转换。这可以代替链接多个 RAC Streams 内置的转换。
@implementation RACStream (MogKit)
- (instancetype)mog_transform:(MOGTransformation)transformation
{
Class class = self.class;
MOGTransformation transformationWithMapToRAC = MOGCompose(transformation, MOGMap(^id(id val) {
return [class return:val];
}));
MOGReducer *reducer = transformationWithMapToRAC(MOGArrayReducer());
return [[self bind:^{
return ^(id value, BOOL *stop) {
id acc = reducer.reduce(reducer.initial(), value, stop);
if (*stop) {
acc = reducer.complete(acc);
}
return [class concat:acc];
};
}] setNameWithFormat:@"[%@] -mog_transform:", self.name];
}
@end
这可以随后用于将一个转换应用到通道中的所有值,如下所示:
NSNumberFormatter *currencyFormatter = [NSNumberFormatter new];
currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
MOGTransformation add100ToIntValuesAndFormatAsCurrency = MOGComposeArray(@[
MOGFilter(StringIsValidInt()),
MOGMap(^id(NSString *string) {
return @([string intValue] + 100);
}),
MOGMap(^id(id val) {
return [currencyFormatter stringFromNumber:val];
})
]);
[[textField.rac_textSignal mog_transform:add100ToIntValuesAndFormatAsCurrency] subscribeNext:^(id x) {
NSLog(@"Number plus 100 = %@", x);
}];
然后这个转换可以被重复使用,而且并不局限于 RACStream
。
您还可以将其作为子模块添加到您的项目中 https://github.com/mhallendal/MogKit.git
并在您的应用程序中包含项目文件。
如果您正在使用类似 -mog_transform:
这样的 Foundation 扩展,例如在 NSArray
上,请确保将 -ObjC
添加到您的应用程序的 其他链接器标志 中。
API 还未锁定,因此可能在 1.0 发布之前略有变化。
对于熟悉 Transducers 的读者来说,这会感觉很熟悉,MogKit 是使用 Transducers 实现的,而 MOGTrasformation
实际上是将 MOGReducer
映射到 MOGReducer
的 transducers。
有关 Transducer 的简介,请参阅 Transducer 简介 和 Clojure 创造者 Clojure - Transducers 以及 Rich Hickey 的演讲 Rich Hickey。