ios - Objective-C:使用可变参数调用选择器

标签 ios objective-c

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

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

该方法负责调用委托(delegate)中的方法。参数是一个选择器。我的问题是选择器可以有 0 - 3 个参数,如下所示。
-(void) handleBluetoothEnabled:(BOOL)aEnabled
{
 if (aEnabled)
 {
  [self.statusDelegate bluetoothEnabled];
  if (_storedPenSerialNumber != nil && ![_storedSerialNumber isEqual:kUnknownPenID])
   {
    [self runAllStatusDelegates: @selector(penConnected : _storedSerialNumber : _storedFirmware:)];
   }
 }
 else
 {
  [self.statusDelegate bluetoothDisabled];
 }
}

-(void) handleChooseDevice:(BluetoothDeviceList*)aDevices
{
 NSLog(@"Handle Choose Device");
 [self runAllStatusDelegates: @selector(chooseDevice:aDevices:)];
}


-(void) handleDiscoveryStarted
{
 NSLog(@"Discovery Started");
 [self runAllStatusDelegates: @selector(searchingForBluetoothDevice)];
 [self.statusDelegate handleStatus:@"Searching for your digipen"];
}

此实现不起作用,因为 performSelector 无法识别选择器。

我还尝试使用 @selector(penConnected::) withObject:_storedSerialNumber 来实现它,但是我还必须使用其他参数来实现另一种方法,我不希望这样。
我是objective-c的新手,所以我对所有可能性都不太熟悉。

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

最佳答案

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

所以我要做的只是将一个 block 传递给你的 runAllStatusDelegates将对所有代表执行的方法:

- (void)performSelector:(SEL)selector againstAllDelegatesWithExecutionBlock:(void (^)(id<StatusDelegate>))blockToExecute
{
    for (id<StatusDelegate> delegate in self.statusDelegates)
    {
        if ([delegate respondsToSelector:selector])
        {
            blockToExecute(delegate);
        }
    }
}

然后当你想用一个函数调用你的代表时,它看起来像这样:
[self performSelector:@selector(handleAnswerOfLifeFound)
againstAllDelegatesWithExecutionBlock:^(id<StatusDelegate> delegate){
    [delegate handleAnswerOfLifeFound];
}];

我想唯一的缺点可能是您可以更改选择器并将不同的函数传递到 block 中。我将如何解决这个问题是通过实际确保并非所有方法都是可选的,或者如果它们是可选的以在 block 内进行实际检查,这将清理签名:
- (void)callAllDelegatesWithBlock:(void (^)(id<StatusDelegate>))blockToExecute
{
    for (id<StatusDelegate> delegate in self.statusDelegates)
    {
            blockToExecute(delegate);
    }
}

然后是可选方法的实际用法:
[self callAllDelegatesWithBlock^(id<StatusDelegate> delegate){
    if([delegate respondsToSelector:@selector(handleAnswerOfLifeFound)]){
        [delegate handleAnswerOfLifeFound];
    }
}];

仍然容易出错,但至少更整洁一些。

关于ios - Objective-C:使用可变参数调用选择器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34174628/

相关文章:

ios - 这段 Swift 代码在做什么? func somefunc(其中 : (_: NSLayoutConstraint) -> Bool)

ios - UISearchBar 在输入文本时不显示任何结果

ios - 如何使 UIControl 在 XCUITest 中显示为按钮?

ios - 如何让 arc4random 在 swift 中选择 4 个不同的名称

iOS( swift ): Core data fetching with relationships

ios - UITableView 在编辑时不显示左侧多选圆圈

ios - 如何为 ipad 显示全屏 ipad

objective-c - 无需输入管理员密码即可进行 Obj-c 协同设计?

ios - UIActivityViewController 或 UIDocumentInteractionController 与 WhatsApp 和 FB

objective-c - 如何使用 NSDateFormatter 将此字符串解析为 NSDate?