Я новичок в iOS. У меня есть метод выбора:
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{
}
Я пытаюсь реализовать что-то вроде этого -
[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];
Но это дает мне ошибку:
Instance method -performSelector:withObject:withObject:afterDelay: not found
Любые идеи относительно того, что мне не хватает?
invoke
звонка:[inv performSelector:@selector(invoke) withObject:nil afterDelay:1];
я согласен, это отличное решение. Всем удачного кодирования!Потому что
[NSObject performSelector:withObject:withObject:afterDelay:]
метода не существует.Вам необходимо инкапсулировать данные, которые вы хотите отправить, в какой-то один объект Objective C (например, NSArray, NSDictionary, некоторый настраиваемый тип Objective C), а затем передать их через
[NSObject performSelector:withObject:afterDelay:]
метод, который хорошо известен и любим.Например:
NSArray * arrayOfThingsIWantToPassAlong = [NSArray arrayWithObjects: @"first", @"second", nil]; [self performSelector:@selector(fooFirstInput:) withObject:arrayOfThingsIWantToPassAlong afterDelay:15.0];
источник
NSNumber * whatToDoNumber = [NSNumber numberWithBool: doThis];
") и передайте его как один параметр, @virata.Вы можете упаковать свои параметры в один объект и использовать вспомогательный метод для вызова исходного метода, как предложили Майкл и другие.
Другой вариант - dispatch_after, который берет блок и ставит его в очередь в определенное время.
double delayInSeconds = 15.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [self fooFirstInput:first secondInput:second]; });
Или, как вы уже обнаружили, если вам не нужна задержка, вы можете просто использовать
- performSelector:withObject:withObject:
источник
__weak
для предоставления своему воображаемому таймеру только слабую связь с собой - так что вы не в конечном итоге искусственно продляете жизненный цикл вашего объекта и, например, если ваш performSelector: afterDelay: влияет на что-то вроде хвоста рекурсия (хотя и без рекурсии), то он разрешает цикл сохранения.Самый простой вариант - изменить ваш метод так, чтобы он принимал один параметр, содержащий оба аргумента, например,
NSArray
илиNSDictionary
(или добавить второй метод, который принимает один параметр, распаковывает его и вызывает первый метод, а затем вызывает второй метод для задержка).Например, у вас может быть что-то вроде:
- (void) fooOneInput:(NSDictionary*) params { NSString* param1 = [params objectForKey:@"firstParam"]; NSString* param2 = [params objectForKey:@"secondParam"]; [self fooFirstInput:param1 secondInput:param2]; }
А затем, чтобы вызвать это, вы можете:
[self performSelector:@selector(fooOneInput:) withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil] afterDelay:15.0];
источник
NSDictionary
теряет безопасность типов. Не идеально.performSelector:
(илиNSInvocation
). Если это вызывает беспокойство, лучшим вариантом, вероятно, будет пройти GCD.- (void) callFooWithArray: (NSArray *) inputArray { [self fooFirstInput: [inputArray objectAtIndex:0] secondInput: [inputArray objectAtIndex:1]]; } - (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second { }
и назовите его:
[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];
источник
Вы можете найти все типы предоставленных методов performSelector: здесь:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html
Есть множество вариантов, но нет версии, которая принимает несколько объектов, а также задержку. Вместо этого вам нужно будет обернуть свои аргументы в NSArray или NSDictionary.
- performSelector: - performSelector:withObject: - performSelector:withObject:withObject: – performSelector:withObject:afterDelay: – performSelector:withObject:afterDelay:inModes: – performSelectorOnMainThread:withObject:waitUntilDone: – performSelectorOnMainThread:withObject:waitUntilDone:modes: – performSelector:onThread:withObject:waitUntilDone: – performSelector:onThread:withObject:waitUntilDone:modes: – performSelectorInBackground:withObject:
источник
Мне не нравится способ NSInvocation, слишком сложный. Давайте оставим это простым и понятным:
// Assume we have these variables id target, SEL aSelector, id parameter1, id parameter2; // Get the method IMP, method is a function pointer here. id (*method)(id, SEL, id, id) = (void *)[target methodForSelector:aSelector]; // IMP is just a C function, so we can call it directly. id returnValue = method(target, aSelector, parameter1, parameter2);
источник
Я просто немного поиграл, и мне нужно было вызвать оригинальный метод. Я сделал протокол и передал ему свой объект. Другой способ - определить метод в категории, но для этого потребуется подавление предупреждения (#pragma clang Diagnosis игнорируется "-Wincomplete-implementation").
источник
Простой и многоразовый способ - расширить
NSObject
и реализовать- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments;
что-то типа:
- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments { NSMethodSignature *signature = [self methodSignatureForSelector: aSelector]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: signature]; [invocation setSelector: aSelector]; int index = 2; //0 and 1 reserved for (NSObject *argument in arguments) { [invocation setArgument: &argument atIndex: index]; index ++; } [invocation invokeWithTarget: self]; }
источник
Я бы просто создал настраиваемый объект, содержащий все мои параметры как свойства, а затем использовал бы этот единственный объект в качестве параметра
источник