Ios Objective-C:使用变量参数调用选择器

Ios Objective-C:使用变量参数调用选择器,ios,objective-c,Ios,Objective C,我面临以下问题,我已经尝试了很多。我还阅读了Stackoverflow中的其他问题,如: 还有关于选择器的核心能力,但我正在寻找将参数变量传递给选择器的最佳方法 -(void) runAllStatusDelegates : (SEL)selector { for (NSValue *val in self.statusDelegates) { id<StatusDelegate> delegate = val; if ([delegate respondsToSelec

我面临以下问题,我已经尝试了很多。我还阅读了Stackoverflow中的其他问题,如: 还有关于选择器的核心能力,但我正在寻找将参数变量传递给选择器的最佳方法

-(void) runAllStatusDelegates : (SEL)selector
{
 for (NSValue *val in self.statusDelegates)
 {
  id<StatusDelegate> delegate = val;
  if ([delegate respondsToSelector:selector])
  { 
   [delegate performSelector:selector];
  }
 }
}
此实现无法工作,因为performSelector无法识别选择器

-(void) runAllStatusDelegates : (SEL)selector
{
 for (NSValue *val in self.statusDelegates)
 {
  id<StatusDelegate> delegate = val;
  if ([delegate respondsToSelector:selector])
  { 
   [delegate performSelector:selector];
  }
 }
}
我还尝试用@selector(penConnected::)和Object:_storedSerialNumber实现它,但是我还必须用附加参数实现另一个方法,我不希望这样。 我是objective-c的新手,所以我不太熟悉所有的可能性


我的想法是将字符串和参数数组传递给runAllStatusDelegates,并在该方法中构建选择器,但这是最好的方法还是有更方便的方法?

在这种情况下,您可以使用NSInvocation

SEL theSelector = @selector(yourSelector:);
NSMethodSignature *aSignature = [NSMethodSignature instanceMethodSignatureForSelector:theSelector];
NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
[anInvocation setSelector:theSelector];
[anInvocation setTarget:self];
[anInvocation setArgument:&arg1 atIndex:2];
[anInvocation setArgument:&arg2 atIndex:3];
[anInvocation setArgument:&arg3 atIndex:4];
[anInvocation setArgument:&arg4 atIndex:5];
//Add more
请注意,索引0和1处的参数是为目标和选择器保留的

-(void) runAllStatusDelegates : (SEL)selector
{
 for (NSValue *val in self.statusDelegates)
 {
  id<StatusDelegate> delegate = val;
  if ([delegate respondsToSelector:selector])
  { 
   [delegate performSelector:selector];
  }
 }
}

有关更多信息,请在本案例中使用NSInvocation

SEL theSelector = @selector(yourSelector:);
NSMethodSignature *aSignature = [NSMethodSignature instanceMethodSignatureForSelector:theSelector];
NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
[anInvocation setSelector:theSelector];
[anInvocation setTarget:self];
[anInvocation setArgument:&arg1 atIndex:2];
[anInvocation setArgument:&arg2 atIndex:3];
[anInvocation setArgument:&arg3 atIndex:4];
[anInvocation setArgument:&arg4 atIndex:5];
//Add more
请注意,索引0和1处的参数是为目标和选择器保留的

-(void) runAllStatusDelegates : (SEL)selector
{
 for (NSValue *val in self.statusDelegates)
 {
  id<StatusDelegate> delegate = val;
  if ([delegate respondsToSelector:selector])
  { 
   [delegate performSelector:selector];
  }
 }
}

有关详细信息,请将参数绑定到选择器

NSDictionary *argInfo=@{@"arg1":arg1,@"arg2":arg2,...};
objc_setAssociatedObject(self,@selector(chooseDevice:aDevices:),argInfo,OBJC_ASSOCIATION_COPY)
[self runAllStatusDelegates: @selector(chooseDevice:aDevices:)];
然后在

-(void) runAllStatusDelegates : (SEL)selector
{
 for (NSValue *val in self.statusDelegates)
 {
  id<StatusDelegate> delegate = val;
  if ([delegate respondsToSelector:selector])
  { 

   NSDictionary *argInfo=objc_getAssociatedObject(self, selector);
   //call the fun use arginfo
  }
 }
}
-(void)runAllStatusDelegates:(SEL)选择器
{
for(NSValue*val在self.statusDelegates中)
{
id delegate=val;
if([委托响应选择器:选择器])
{ 
NSDictionary*argInfo=objc_getAssociatedObject(self,选择器);
//称之为乐趣的使用
}
}
}

您可以将参数绑定到选择器

NSDictionary *argInfo=@{@"arg1":arg1,@"arg2":arg2,...};
objc_setAssociatedObject(self,@selector(chooseDevice:aDevices:),argInfo,OBJC_ASSOCIATION_COPY)
[self runAllStatusDelegates: @selector(chooseDevice:aDevices:)];
然后在

-(void) runAllStatusDelegates : (SEL)selector
{
 for (NSValue *val in self.statusDelegates)
 {
  id<StatusDelegate> delegate = val;
  if ([delegate respondsToSelector:selector])
  { 

   NSDictionary *argInfo=objc_getAssociatedObject(self, selector);
   //call the fun use arginfo
  }
 }
}
-(void)runAllStatusDelegates:(SEL)选择器
{
for(NSValue*val在self.statusDelegates中)
{
id delegate=val;
if([委托响应选择器:选择器])
{ 
NSDictionary*argInfo=objc_getAssociatedObject(self,选择器);
//称之为乐趣的使用
}
}
}

我个人不喜欢复杂签名的
NSInvocation
。它非常适合将一个简单的函数调用排入队列,并在需要时运行它,但对于您的情况,您知道选择器,因此不需要执行调用路径。我通常发现,如果您实际上不知道要在编译时调用的选择器,调用会更有用,可能是由您的API等决定的

因此,我要做的只是将一个块传递到
runAllStatusDelegates
方法中,该方法将对所有代理执行:

- (void)performSelector:(SEL)selector againstAllDelegatesWithExecutionBlock:(void (^)(id<StatusDelegate>))blockToExecute
{
    for (id<StatusDelegate> delegate in self.statusDelegates)
    {
        if ([delegate respondsToSelector:selector])
        {
            blockToExecute(delegate);
        }
    }
}
-(void)执行选择器:(SEL)选择器重新安装并删除执行块:(void(^)(id))块以执行
{
for(id代表在self.statusDelegates中)
{
if([委托响应选择器:选择器])
{
区块执行(委托);
}
}
}
然后,当您想使用函数调用您的代理时,它如下所示:

[self performSelector:@selector(handleAnswerOfLifeFound)
againstAllDelegatesWithExecutionBlock:^(id<StatusDelegate> delegate){
    [delegate handleAnswerOfLifeFound];
}];
[自执行选择器:@selector(handleAnswerOfLifeFound)
AgaInstallDelegates执行块:^(id委托){
[delegate handleAnswerOfLifeFound];
}];
我想唯一的缺点可能是您可以更改选择器并将不同的函数传递到块中。我将如何解决这个问题,是通过确保并非所有方法都是可选的,或者如果它们是可选的,可以在块内进行实际检查,这将清除签名:

- (void)callAllDelegatesWithBlock:(void (^)(id<StatusDelegate>))blockToExecute
{
    for (id<StatusDelegate> delegate in self.statusDelegates)
    {
            blockToExecute(delegate);
    }
}
-(void)调用AllDelegateswithBlock:(void(^)(id))块执行
{
for(id代表在self.statusDelegates中)
{
区块执行(委托);
}
}
然后是可选方法的实际使用情况:

[self callAllDelegatesWithBlock^(id<StatusDelegate> delegate){
    if([delegate respondsToSelector:@selector(handleAnswerOfLifeFound)]){
        [delegate handleAnswerOfLifeFound];
    }
}];
[self callAllDelegatesWithBlock^(id委托){
if([delegate respondsToSelector:@selector(HandleanSRofLifeFound)]){
[delegate handleAnswerOfLifeFound];
}
}];

仍然容易出错,但至少有点整洁。

我个人不喜欢复杂签名的
NSInvocation
。它非常适合将一个简单的函数调用排入队列,并在需要时运行它,但对于您的情况,您知道选择器,因此不需要执行调用路径。我通常发现,如果您实际上不知道要在编译时调用的选择器,调用会更有用,可能是由您的API等决定的

因此,我要做的只是将一个块传递到
runAllStatusDelegates
方法中,该方法将对所有代理执行:

- (void)performSelector:(SEL)selector againstAllDelegatesWithExecutionBlock:(void (^)(id<StatusDelegate>))blockToExecute
{
    for (id<StatusDelegate> delegate in self.statusDelegates)
    {
        if ([delegate respondsToSelector:selector])
        {
            blockToExecute(delegate);
        }
    }
}
-(void)执行选择器:(SEL)选择器重新安装并删除执行块:(void(^)(id))块以执行
{
for(id代表在self.statusDelegates中)
{
if([委托响应选择器:选择器])
{
区块执行(委托);
}
}
}
然后,当您想使用函数调用您的代理时,它如下所示:

[self performSelector:@selector(handleAnswerOfLifeFound)
againstAllDelegatesWithExecutionBlock:^(id<StatusDelegate> delegate){
    [delegate handleAnswerOfLifeFound];
}];
[自执行选择器:@selector(handleAnswerOfLifeFound)
AgaInstallDelegates执行块:^(id委托){
[delegate handleAnswerOfLifeFound];
}];
我想唯一的缺点可能是您可以更改选择器并将不同的函数传递到块中。我将如何解决这个问题,是通过确保并非所有方法都是可选的,或者如果它们是可选的,可以在块内进行实际检查,这将清除签名:

- (void)callAllDelegatesWithBlock:(void (^)(id<StatusDelegate>))blockToExecute
{
    for (id<StatusDelegate> delegate in self.statusDelegates)
    {
            blockToExecute(delegate);
    }
}
-(void)调用AllDelegateswithBlock:(void(^)(id))块执行
{
for(id代表在self.statusDelegates中)
{
区块执行(委托);
}
}
然后是可选方法的实际使用情况:

[self callAllDelegatesWithBlock^(id<StatusDelegate> delegate){
    if([delegate respondsToSelector:@selector(handleAnswerOfLifeFound)]){
        [delegate handleAnswerOfLifeFound];
    }
}];
[self callAllDelegatesWithBlock^(id委托){
if([delegate respondsToSelector:@selector(HandleanSRofLifeFound)]){
[delegate handleAnswerOfLifeFound];
}
}];

仍然容易出错,但至少有点整洁。

将数组或字典传递给它?我很好奇为什么使用选择器而不显式调用函数?我在不同的控制器中使用相同的委托。我有一个包含这些委托的哈希表,我想调用一个方法来执行所有委托。这就是为什么我