Objective C привязка параметров во время выполнения - PullRequest
0 голосов
/ 11 ноября 2009

Я бы хотел (во время выполнения) связать параметр с функцией, как вы можете это сделать в boost :: bind - примерно так:

-(void)myFuncWithParameter:(NSString*)param {
   NSLog(param);
}

-(void)init {

   UIButton *helloButton = [UIButton buttonWithType:UIButtonTypeCustom];
   [helloButton addTarget:self action:@selector(myFuncWithParameter:@"hello") forControlEvents:UIControlEventTouchUpInside];

}

Итак ... Я динамически связываю (во время выполнения) значение @ "hello" с параметром.

Очевидно, что приведенный выше не правильный синтаксис. Кто-нибудь знает, возможно ли это и правильный ли синтаксис?

Ура, Ник.

Ответы [ 2 ]

3 голосов
/ 11 ноября 2009

Короткий ответ - нет или, по крайней мере, не на этом уровне.

Длинный ответ заключается в том, что технически возможно создать что-то похожее на использование NSInvocations (и / или forwardInvocation:), делать что-то умное в methodForSelector: и или динамически регистрировать реализации метода, но это очень сложно, особенно если Вы беспокоитесь о скорости.

Если бы у меня был какой-то код, в котором создание таких методов с карри было бы действительно полезным, я бы сделал что-то вроде этого (написано в этом комментарии, не проверено);

//FIXME: In a real implementation you would do some mangling, this code will get confused if you have _s in the curried selector, and thus could be exploitable

//This method makes a unique selector by mangling the arguments
- (SEL) selectorForSelector:(SEL)bindSel withString:(NSString *)bindString {
  NSString *mangle = [NSString *stringWithFormat:@"LGBind_%@_%@"], NSStringFromSelector(bindSel), bindString];
  SEL retval = NSSelectorFromString(mangle);

  //Register the imp. You probably want to check if it is already reg
  if (![self respondsToSelector:retval]) {
    class_addMethod([self class], retval, LGBind_IMP, "v@:")l
  }
}

//Generic dispatcher imp
void LGBind_IMP(id self, SEL _cmd) {
  NSString *selectorName = NSStringFromSelector(_cmd);
  NSArray *array [selectorName componentsSeparatedByString:@"_"];

  //Skip index 0; it is @"LGBind"
  NSString *originalSelectorString = [array objectAtIndex:1];
  NSString *originalArgString = [array objectAtIndex:2];

  //Get our the SEL and the IMP
  SEL originalSEL = NSSelectorFromString(originalSelectorString);
  IMP originalIMP = [self methodForSelector:originalSEL];

  //call the original imp
  originalIMP([self class], originalSEL, originalArgString);
}

Очевидно, что в зависимости от ваших конкретных потребностей вы могли бы делать что-то где-то по-другому, например, вы могли бы лениво работать с бесами в forwardInvocation или хранить данные об управляемом селекторе в dict в экземпляре, вместо того, чтобы просто перенести его в имя селектора.

1 голос
/ 11 ноября 2009

Общий ответ заключается в том, что механизм целевого действия допускает только цель, отправителя и сообщение, которое принимает отправителя; следовательно, если вам нужен доступ к данным, вы должны получить их от получателя или отправителя.

Один из вариантов - создать класс, представляющий привязку значения параметра, метода и объекта. Этот класс будет иметь действие, которое вызывает метод объекта, передавая значение. Используйте экземпляр этого класса в качестве цели. Вот упрощенный пример:

@interface UnaryBinder : NSObject {
    id target;
    SEL selector;
    id parameter;
}
@property id target;
@property SEL selector;
@property (retain) id parameter;
-(id)initWithTarget:(id)anObject selector:(SEL)aSelector param:(id)aParameter;
-(void)action:(id)sender;
@end

@implementation UnaryBinder
...
-(void)action:(id)sender {
    [target performSelector:selector withObject:parameter];
}
@end

Если вы хотите поддерживать произвольное количество параметров, вам нужно использовать NSInvocation (как упоминает Луи) вместо performSelector:withObject. Конечно, элементы управления не сохраняют свои цели, поэтому вам нужен какой-то способ сохранить UnaryBinder. В этот момент вы можете также пропустить специальный класс и просто сохранить данные в элементе управления, как вы упомянули в своем комментарии об использовании KVP. В качестве альтернативы, выделите действие в класс контроллера и используйте его экземпляр в качестве цели. UnaryBinder и его аналог на самом деле не дают никаких преимуществ, когда дело доходит до target-action. Для связанных тем, Google "сообщения высшего порядка".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...