1. keroxp

    Posted

    keroxp
Changes in title
+NSArray+Pluck
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,80 @@
+
+Underscore.jsにarray.pluckというとても便利なメソッドがある。
+
+```javascript
+var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
+_.pluck(stooges, 'name');
+// => ["moe", "larry", "curly"]
+```
+
+あまりにも便利すぎるのでObjective-Cでも使いたくなったので実装した。
+多分n番煎じだと思う。
+cocoaにはvalueForKeyPath:という便利なアクセッサがあるので、入れ子になったNSDictionaryやオブジェクトなどのプロパティも比較できる。
+
+```objectivec:NSArray+Pluck.h
+@interface NSArray (Pluck)
+
+- (NSArray*)pluckUsingSelector:(SEL)selector value:(id)value;
+- (NSArray*)pluckForKeyPath:(NSString*)keyPath comparingSelector:(SEL)selector value:(id)value;
+
+@end
+
+```
+```objectivec:NSArray+Pluck.m
+#import <objc/message.h>
+
+@implementation NSArray (Pluck)
+
+- (NSArray *)pluckUsingSelector:(SEL)selector value:(id)value
+{
+ return [self pluckForKeyPath:nil comparingSelector:selector value:value];
+}
+
+- (NSArray *)pluckForKeyPath:(NSString *)keyPath comparingSelector:(SEL)selector value:(id)value
+{
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:self.count];
+ for (id obj in self) {
+ id target = keyPath ? [obj valueForKeyPath:keyPath] : obj;
+ if ([target respondsToSelector:selector]){
+ if(objc_msgSend(target, selector, value)) {
+ [array addObject:obj];
+ }
+ }
+ }
+ return [NSArray arrayWithArray:array];
+}
+
+@end
+
+```
+
+こんな感じで使えます。
+
+```objectivec:NSARray+PluckTests.m
+- (void)testBasic
+{
+ NSArray *a = @[@"a",@"b",@"c",@"ab",@"cd",@"a"];
+ NSArray *p = [a pluckUsingSelector:@selector(isEqualToString:) value:@"a"];
+ XCTAssert(p.count == 2, );
+ for (NSString *s in p) {
+ XCTAssert([s isEqualToString:@"a"], );
+ }
+}
+
+- (void)testKeyPath
+{
+ NSArray *a = @[
+ @{@"hoge": @"hogeval"},
+ @{@"fuga" : @"fugaval"},
+ @{@"var" : @"varval"},
+ @{@"hoga" : @"hogaval"},
+ @{@"hoge": @"hogeval2"}
+ ];
+ NSArray *p1 = [a pluckUsingSelector:@selector(objectForKey:) value:@"hoge"];
+ XCTAssert(p1.count == 2, @"key hogeを持っているのは一つだけ");
+ NSArray *p2 = [a pluckUsingSelector:@selector(isKindOfClass:) value:[NSDictionary class]];
+ XCTAssert(p2.count == a.count, @"全部辞書形");
+ NSArray *p3 = [a pluckForKeyPath:@"hoge" comparingSelector:@selector(isEqualToString:) value:@"hogeval"];
+ XCTAssert(p3.count == 1, @"key hogeの値がhogevalなのは1つだけ");
+}
+```