【问题标题】:SEL performSelector and argumentsSEL performSelector 和参数
【发布时间】:2010-04-26 19:12:19
【问题描述】:

当你只有一个 SEL 对象时,似乎应该有一种简单的方法来调用带有一些参数的选择器。我似乎找不到正确的语法。

-(MyClass*) init: (SEL)sel owner:(NSObject*) parent
{
   int i =10;
   [parent performSelector:sel:i  ];
}

【问题讨论】:

    标签: iphone objective-c selector


    【解决方案1】:

    查看NSObject 文档。在这种情况下:

    [parent performSelector:sel withObject:[NSNumber numberWithInt:i]];
    

    (注意这个方法实际上列在NSObject protocol 文档中)。由于-[NSObject performSelector:withObject:] 需要一个对象参数,因此您必须在父类中编写一个包装器,例如

    -(void)myMethodForNumber:(NSNumber*)number {
        [self myMethod:[number intValue]];
    }
    

    拆箱NSNumber

    如果你真的想直接调用一个接受非对象参数的方法(例如,你无法控制被调用者源并且不想添加类别),你可以使用NSInvocation

    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[parent methodSignatureForSelector:sel]];
    [inv setSelector:sel];
    [inv setTarget:parent];
    [inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv invoke];
    

    附带说明,您的方法看起来像 init 方法,但不遵循 Objective-C 的正确初始化模式。您需要调用超类初始化程序,并且需要测试该调用的nil 结果,并且必须从初始化程序方法返回 self。在所有情况下,您的 Objective-C 初始化方法应如下所示:

    -(id)myInitMethod {
        self = [super init];
        if(self != nil) {
          //perform initialization of self
        }
    
        return self;
    }
    

    您的方法(如果是 init 方法)将如下所示:

    -(id) init: (SEL)sel owner:(NSObject*) parent
    {
       self = [super init];
       if(self != nil) {
           int i = 10;
           NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[parent methodSignatureForSelector:sel]];
           [inv setSelector:sel];
           [inv setTarget:parent];
           [inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
           [inv invoke];
       }
    
        return self;
    }
    

    为了更符合 Objective-C 风格,我也将初始化器重命名为 -(id)initWithSelector:owner:

    【讨论】:

    • 谢谢,这已经超越了。我猜想我可能需要使用 NSInvocation 但不确定。很好的答案。
    • 顺便说一句,即使您无法控制被调用方,您仍然可以使用该类上的类别编写包装方法,将对象拆箱为原始类型。
    • 一个错误 - [inv setSelector:inv]; 应该是 [inv setSelector:sel];?
    【解决方案2】:

    Barry Wark 说的很棒.. 我刚刚修改了针对懒惰程序员的讨论

    -(void)myMethodWith:(int)number andBOOL:(BOOL) someBool andStr:(NSString *)str{
        NSLog(@"%d %d %@",number,someBool,str);
    }
    
    -(void) testMethod{
        SEL sel = @selector(myMethodWith:andBOOL:andStr:);
        int i = 10;
        BOOL bol = YES;
        NSString *str = @"hey baby !";
        NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]];
        [inv setSelector:sel];
        [inv setTarget:self];
        [inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
        [inv setArgument:&bol atIndex:3];
        [inv setArgument:&str atIndex:4];
        [inv invoke];
    }
    

    【讨论】:

    • yunas,我尝试了您的 NSInvocation 代码。六年过去了,你可能处于不同的头脑中,但如果你能抽出一点时间,也许你会看到我错过了什么。谢谢stackoverflow.com/q/51734605/2348597
    【解决方案3】:

    您想使用performSelector:withObject: 棘手的部分是将int 转换为NSObject。您不能将 performSelector 与采用 int 参数的消息一起使用,而必须采用 id

    来自NSObject Protocol Reference

    aSelector 应该标识一个采用 id 类型的单个参数的方法。对于具有其他参数类型和返回值的方法,请使用NSInvocation

    一旦做出改变,您可以:

    id arg = [NSNumber numberWithInt:10];    
    [parent performSelector:sel withObject:arg];
    

    【讨论】:

      【解决方案4】:

      你可以使用:

      - (id)performSelector:(SEL)aSelector withObject:(id)anObject
      - (id)performSelector:(SEL)aSelector withObject:(id)anObject  withObject:(id)anotherObject
      

      或者如果您需要使用更复杂的方法,请使用NSInvocation

      【讨论】:

        【解决方案5】:

        对于将一个或两个id 类型的对象作为参数的方法,您可以使用:

        [parent performSelector:sel withObject:argument1];
        

        [parent performSelector:sel withObject:argument1 withObject:argument2];
        

        对于其他参数类型的方法,创建一个NSInvocation,可以封装任意方法调用。

        【讨论】:

        • 一定要量化确切的方法签名,例如NSSelectorFromFromString(methodWithArg1:arg2:)
        猜你喜欢
        • 1970-01-01
        • 2012-08-13
        • 2012-01-16
        • 1970-01-01
        • 2012-06-24
        • 1970-01-01
        • 1970-01-01
        • 2011-06-27
        • 1970-01-01
        相关资源
        最近更新 更多