Как применить список аргументов к блоку в Objective C? - PullRequest
3 голосов
/ 14 октября 2011

Есть ли в Objective C такая функция, как Smalltalk Block valueWithArguments?

Я ищу функцию с такой подписью:

apply(^(), NSArray* args)

В качестве альтернативы есть способ вызоваселектор списка аргументов?

Ответы [ 2 ]

2 голосов
/ 14 октября 2011

С блоками вам, вероятно, придется совершить магию va_args. Вызов селектора с переменными аргументами может быть выполнен, но вы, вероятно, захотите, чтобы некоторые помощники сделали его менее болезненным.

NSObject + performSelectorWithArgsArray.h

@interface NSObject (performSelectorWithArgsArray)
- (id)performSelector:(SEL)sel withArgsArray:(NSArray *)args;
@end

NSObject + performSelectorWithArgsArray.m

@implementation NSObject (performSelectorWithArgsArray)
- (id)performSelector:(SEL)sel withArgsArray:(NSArray *)args {
  NSInvocation *inv = [NSInvocation invocationWithMethodSignature:
                       [self methodSignatureForSelector:sel]];
  [inv setSelector:sel];
  [inv setTarget:self];
  for (int i = 0; i < args.count; i++) {
    id a = [args objectAtIndex:i];
    [inv setArgument:&a atIndex:2 + i]; // 0 is target, 1 is cmd-selector
  }
  [inv invoke];

  NSNumber *r;
  [inv getReturnValue:&r];
  return r;
}
@end

А затем используйте это так:

#import "NSObject+performSelectorWithArgs.h"

@interface SomeClass : NSObject
@end

@implementation SomeClass
- (NSNumber *)withA:(NSNumber *)a withB:(NSNumber *)b {
  return [NSNumber numberWithInt:a.intValue + b.intValue];
}
@end

- (void)someMethod {
  SomeClass *a = [[SomeClass alloc] init];
  SEL sel = @selector(withA:withB:);
  NSArray *args = [NSArray arrayWithObjects:
                   [NSNumber numberWithInt:2],
                   [NSNumber numberWithInt:3],
                   nil];
  NSNumber *r = [a performSelector:sel withArgsArray:args];
  NSLog(@"%d", r.intValue);
}

Если вы решите сделать что-то подобное, я рекомендую вам действительно прочитать о том, как работает NSInvocation, поскольку он может сильно кусаться. Не уверен, что это можно сделать, не требуя, чтобы все аргументы и возвращаемое значение были объектами.

2 голосов
/ 14 октября 2011

NSArray имеет методы enumerateObjectsUsingBlock: и enumerateObjectsWithOptions:usingBlock: это то, что вы ищете?

[[NSArray arrayWithObjects:@"a", @"b", @"c", nil]
 enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  NSLog(@"%d: %@", idx, obj);
}];
...