SEL performSelector и аргументы

Кажется, что должен быть простой способ назвать селектор с некоторыми аргументами, когда все, что Вы имеете, является объектом SEL. Я, может казаться, не нахожу правильный синтаксис.

-(MyClass*) init: (SEL)sel owner:(NSObject*) parent
{
   int i =10;
   [parent performSelector:sel:i  ];
}
28
задан Keavon 18 May 2014 в 05:54
поделиться

4 ответа

Взгляните на документацию 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;
}

Ваш метод (если это метод инициализации) будет выглядеть так:

-(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: также владелец: .

76
ответ дан 28 November 2019 в 02:23
поделиться

Вы можете использовать:

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

Или, если вам нужно использовать более сложный метод, используйте NSInvocation class

{{1} }
1
ответ дан 28 November 2019 в 02:23
поделиться

Для методы, которые принимают один или два объекта типа id в качестве аргументов, вы можете использовать:

[parent performSelector:sel withObject:argument1];

или

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

Для методов с другими типами аргументов создайте NSInvocation , который может инкапсулировать произвольные вызовы методов.

1
ответ дан 28 November 2019 в 02:23
поделиться

Вы хотите использовать performSelector: withObject: Сложная часть - это преобразование int в NSObject . Вы не можете использовать performSelector с сообщениями, которые принимают int params, вместо этого он должен принимать id .

Из Справочника по протоколу NSObject :

aSelector должен идентифицировать метод, который принимает единственный аргумент типа id. Для методов с другими типами аргументов и возвращаемыми значениями используйте NSInvocation .

После внесения этого изменения вы можете сделать:

id arg = [NSNumber numberWithInt:10];    
[parent performSelector:sel withObject:arg];
3
ответ дан 28 November 2019 в 02:23
поделиться