NSObject
Metoda performSelector:withObject:afterDelay:
pozwala mi wywołać metodę na obiekt z argumentem obiektu po pewnym czasie. Nie można jej używać dla metod z argumentem niebędącym przedmiotem (np. Ints, floats, structs, non-object pointers itp.).
Jaki jest najprostszy sposób osiągnięcia tego samego za pomocą metody z argumentem niebędącym przedmiotem? Wiem, że na performSelector:withObject:
co dzień rozwiązaniem jest użycie NSInvocation
(co przy okazji jest naprawdę skomplikowane). Ale nie wiem, jak sobie poradzić z częścią „opóźnienia”.
Dzięki,
objective-c
cocoa
user102008
źródło
źródło
Odpowiedzi:
Oto, co zwykłem nazywać czymś, czego nie mogłem zmienić za pomocą NSInvocation:
źródło
[theMovie setOrientation: UIInterfaceOrientationPortrait animated:NO]
? Czy masz na myśli, żeinvoke
wiadomość jest w metodzie, którą wykonujesz po opóźnieniu?Po prostu zawiń float, boolean, int lub podobny w NSNumber.
W przypadku struktur nie znam wygodnego rozwiązania, ale możesz stworzyć osobną klasę ObjC, która będzie właścicielem takiej struktury.
źródło
nil
doBOOL
parametru, aby otrzymaćNO
(FALSE
)NIE UŻYWAJ TEJ ODPOWIEDZI. POZOSTAWIŁEM JEDYNIE W CELACH HISTORYCZNYCH. ZOBACZ PONIŻSZE UWAGI.
Istnieje prosta sztuczka, jeśli jest to parametr typu BOOL.
Pomiń zero na NIE, a siebie na TAK. zero jest rzutowane na wartość BOOL NO. self jest rzutowane na wartość BOOL równą YES.
To podejście nie działa, jeśli jest czymś innym niż parametr BOOL.
Zakładając, że ja jest UIView.
źródło
if ()
na nim test, ale można sobie wyobrazić, że jakiś kod będzie zależał od tego, że będzie 0 lub 1, a zatem wygrywa nie traktuj dużej wartości adresu jako takiej samej jak 1 (TAK).self
taki adres0x0123400
. Dzięki temu podejściu NIE otrzymasz TAK w 0,4% przypadków. Co gorsza, z takim prawdopodobieństwem to rozwiązanie może przejść wszystkie testy i ujawnić się później.Być może NSValue , po prostu upewnij się, że wskaźniki są nadal aktualne po opóźnieniu (tj. Nie ma obiektów przydzielonych na stosie).
źródło
NSValue
(jeśli to możliwe) zgodnie z oczekiwaniamitype
?Wiem, że to stare pytanie, ale jeśli tworzysz iOS SDK 4+, możesz użyć bloków, aby to zrobić przy niewielkim wysiłku i uczynić go bardziej czytelnym:
źródło
PerformSelector: WithObject zawsze pobiera obiekt, więc aby przekazać argumenty takie jak int / double / float itp ..... Możesz użyć czegoś takiego.
W ten sam sposób możesz użyć [NSNumber numberWithInt:] etc .... iw metodzie odbioru możesz przekonwertować liczbę na swój format jako [number int] lub [number double].
źródło
Bloki są do zrobienia. Możesz mieć złożone parametry, bezpieczeństwo typów i jest to o wiele prostsze i bezpieczniejsze niż większość starych odpowiedzi tutaj. Na przykład możesz po prostu napisać:
Bloki umożliwiają przechwytywanie dowolnych list parametrów, obiektów referencyjnych i zmiennych.
Implementacja wspierająca (podstawowa):
Przykład:
Zobacz także odpowiedź Michaela (+1) dla innego przykładu.
źródło
Zawsze zalecałbym używanie NSMutableArray jako obiektu do przekazania. Dzieje się tak, ponieważ możesz następnie przekazać kilka obiektów, takich jak naciśnięty przycisk i inne wartości. NSNumber, NSInteger i NSString to tylko kontenery o pewnej wartości. Upewnij się, że po uzyskaniu obiektu z tablicy, do której się odwołujesz, do odpowiedniego typu kontenera. Musisz przekazać kontenery NS. Tam możesz sprawdzić wartość. Pamiętaj, że kontenery używają isEqual podczas porównywania wartości.
źródło
Ja też chciałem to zrobić, ale metodą, która otrzymuje parametr BOOL. Zawijanie wartości bool przy użyciu NSNumber NIE POWIODŁO SIĘ DO PRZESŁANIA WARTOŚCI. Nie mam pojęcia dlaczego.
Skończyło się na tym, że zrobiłem prosty hack. Umieściłem wymagany parametr w innej funkcji fikcyjnej i wywołałem tę funkcję za pomocą performSelector, gdzie withObject = nil;
źródło
-performSelector[...]
metoda oczekuje obiektu (zamiast pierwotnego typu danych) i nie wie, że wywoływany selektor akceptuje wartość logiczną, być może adres (wartość wskaźnika)NSNumber
instancji jest ślepo „rzutowany” naBOOL
(= niezerowe, tjTRUE
.). Być może środowisko wykonawcze mogłoby być sprytniejsze niż to i rozpoznać zerową wartość logiczną opakowaną wNSNumber
!Uważam, że najszybszym (ale nieco brudnym) sposobem na to jest bezpośrednie wywołanie objc_msgSend. Jednak wywołanie go bezpośrednio jest niebezpieczne, ponieważ musisz przeczytać dokumentację i upewnić się, że używasz prawidłowego wariantu dla typu wartości zwracanej, a ponieważ objc_msgSend jest zdefiniowany jako vararg dla wygody kompilatora, ale w rzeczywistości jest zaimplementowany jako szybki klej montażowy . Oto kod używany do wywołania metody delegata - [delegate integerDidChange:], która przyjmuje pojedynczy argument będący liczbą całkowitą.
Najpierw zapisuje selektor, ponieważ będziemy odwoływać się do niego wiele razy i łatwo byłoby wprowadzić literówkę. Następnie sprawdza, czy delegat faktycznie odpowiada selektorowi - może to być protokół opcjonalny. Następnie tworzy typ wskaźnika funkcji, który określa rzeczywistą sygnaturę selektora. Należy pamiętać, że wszystkie komunikaty Objective-C mają dwa ukryte pierwsze argumenty, wysyłany obiekt i wysyłany selektor. Następnie tworzymy wskaźnik funkcji odpowiedniego typu i ustawiamy go tak, aby wskazywał na podstawową funkcję objc_msgSend. Pamiętaj, że jeśli zwracana wartość jest zmiennoprzecinkową lub strukturą, musisz użyć innego wariantu objc_msgSend. Na koniec wyślij wiadomość za pomocą tej samej maszyny, której używa Objective-C pod arkuszami.
źródło
Możesz po prostu użyć NSTimer do wywołania selektora:
źródło
yourMethod:
w twoim przykładzie jest sam licznik czasu, a nie przekazałeś niczego dlauserInfo
. Nawet gdybyś użyłuserInfo
, nadal musiałbyś podnosić wartość, jak sugerował Harms i Remus Rusanu.Wywołanie performSelector z NSNumber lub innym NSValue nie zadziała. Zamiast używać wartości NSValue / NSNumber, efektywnie rzutuje wskaźnik na int, float lub cokolwiek innego i używa tego.
Ale rozwiązanie jest proste i oczywiste. Utwórz NSInvocation i wywołaj
[invocation performSelector:@selector(invoke) withObject:nil afterDelay:delay]
źródło
Pehaps ... ok, bardzo prawdopodobne, że czegoś mi brakuje, ale dlaczego nie utworzyć po prostu typu obiektu, powiedzmy NSNumber, jako kontenera dla zmiennej niebędącej typem obiektowym, takiej jak CGFloat?
źródło