Jestem nowicjuszem na iOS. Mam następującą metodę selektora -
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{
}
Próbuję zaimplementować coś takiego -
[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];
Ale to daje mi błąd, mówiąc:
Instance method -performSelector:withObject:withObject:afterDelay: not found
Jakieś pomysły, czego mi brakuje?
iphone
ios
selector
performselector
Suchi
źródło
źródło
invoke
dzwonić:[inv performSelector:@selector(invoke) withObject:nil afterDelay:1];
Muszę się zgodzić, że to świetne rozwiązanie. Miłego kodowania wszystkim!Ponieważ nie ma czegoś takiego jak
[NSObject performSelector:withObject:withObject:afterDelay:]
metoda.Musisz umieścić dane, które chcesz wysłać, do pojedynczego obiektu Objective C (np. NSArray, NSDictionary, jakiś niestandardowy typ Objective C), a następnie przekazać je
[NSObject performSelector:withObject:afterDelay:]
metodą, która jest dobrze znana i lubiana.Na przykład:
NSArray * arrayOfThingsIWantToPassAlong = [NSArray arrayWithObjects: @"first", @"second", nil]; [self performSelector:@selector(fooFirstInput:) withObject:arrayOfThingsIWantToPassAlong afterDelay:15.0];
źródło
NSNumber * whatToDoNumber = [NSNumber numberWithBool: doThis];
”) I przekaż go jako jedyny parametr @virata.Możesz spakować swoje parametry w jeden obiekt i użyć metody pomocniczej, aby wywołać swoją oryginalną metodę, jak zasugerował Michael i inni.
Inną opcją jest dispatch_after, który pobierze blok i umieści go w kolejce w określonym czasie.
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]; });
Lub, jak już odkryłeś, jeśli nie potrzebujesz opóźnienia, możesz po prostu użyć
- performSelector:withObject:withObject:
źródło
__weak
aby dać swojemu zegarowi udawanego tylko słabe łącze z powrotem do siebie - więc nie kończysz sztucznie przedłużając cykl życia obiektu i np. Jeśli twój performSelector: afterDelay: powoduje coś podobnego do tail rekurencja (aczkolwiek bez rekursji) to rozwiązuje cykl utrzymania.Najprostszą opcją jest zmodyfikowanie metody tak, aby pobierała pojedynczy parametr zawierający oba argumenty, na przykład
NSArray
lubNSDictionary
(lub dodać drugą metodę, która przyjmuje pojedynczy parametr, rozpakowuje go i wywołuje pierwszą metodę, a następnie wywołuje drugą metodę w opóźnienie).Na przykład możesz mieć coś takiego:
- (void) fooOneInput:(NSDictionary*) params { NSString* param1 = [params objectForKey:@"firstParam"]; NSString* param2 = [params objectForKey:@"secondParam"]; [self fooFirstInput:param1 secondInput:param2]; }
A potem, aby to nazwać, możesz zrobić:
[self performSelector:@selector(fooOneInput:) withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil] afterDelay:15.0];
źródło
NSDictionary
utratę bezpieczeństwa typów. Nieidealny.performSelector:
(lubNSInvocation
). Jeśli jest to problem, najlepszą opcją byłoby prawdopodobnie przejście przez GCD.- (void) callFooWithArray: (NSArray *) inputArray { [self fooFirstInput: [inputArray objectAtIndex:0] secondInput: [inputArray objectAtIndex:1]]; } - (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second { }
i zadzwoń z:
[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];
źródło
Wszystkie typy dostępnych metod performSelector: można znaleźć tutaj:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html
Istnieje wiele odmian, ale nie ma wersji, która pobiera wiele obiektów, a także opóźnienie. Zamiast tego będziesz musiał zawrzeć swoje argumenty w NSArray lub 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:
źródło
Nie podoba mi się sposób NSInvocation, zbyt złożony. Niech to będzie proste i przejrzyste:
// 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);
źródło
Po prostu zawirowałem i musiałem wywołać oryginalną metodę. Robiłem protokół i rzucałem na niego mój obiekt. Innym sposobem jest zdefiniowanie metody w kategorii, ale wymagałoby to pominięcia ostrzeżenia (zignorowano #pragma clang diagnostyka „-Wincomplete-Implementation”).
źródło
Prostym sposobem wielokrotnego użytku jest rozszerzenie
NSObject
i wdrożenie- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments;
coś jak:
- (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]; }
źródło
Po prostu utworzyłbym obiekt niestandardowy zawierający wszystkie moje parametry jako właściwości, a następnie użyłbym tego pojedynczego obiektu jako parametru
źródło