Próbuję utworzyć NSTimer
w, Swift
ale mam pewne problemy.
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test()
jest funkcją w tej samej klasie.
W edytorze pojawia się błąd:
Nie można znaleźć przeciążenia dla parametru „init”, które akceptuje podane argumenty
Kiedy przejdę selector: test()
do selector: nil
błędu znika.
Próbowałem:
selector: test()
selector: test
selector: Selector(test())
Ale nic nie działa i nie mogę znaleźć rozwiązania w referencjach.
selector: test()
wywołatest
i przekaże wartośćselector
argumentu do argumentu.Odpowiedzi:
Sam Swift nie używa selektorów - kilka wzorców projektowych, które w Objective-C wykorzystują selektory, działa inaczej w Swift. (Na przykład użyj opcjonalnego tworzenia łańcuchów dla typów protokołów lub
is
/as
testów zamiastrespondsToSelector:
i używaj zamknięć gdziekolwiek możesz zamiastperformSelector:
dla lepszego bezpieczeństwa typu / pamięci.)Ale wciąż istnieje wiele ważnych interfejsów API opartych na ObjC, które używają selektorów, w tym liczniki czasu i wzorzec celu / działania. Swift zapewnia
Selector
typ pracy z nimi. (Swift automatycznie wykorzystuje to zamiast typu ObjCSEL
.)W Swift 2.2 (Xcode 7.3) i nowszych (w tym Swift 3 / Xcode 8 i Swift 4 / Xcode 9):
Za
Selector
pomocą#selector
wyrażenia można zbudować funkcję typu Swift .Wspaniała rzecz w tym podejściu? Odniesienie funkcja jest sprawdzana przez kompilator Swift, więc można użyć
#selector
wyrażenia tylko z parami klasy / metody, które rzeczywiście istnieją i są uprawnione do stosowania jako selektorów (patrz „dostępność Selector” poniżej). Możesz również dowolnie określać odwołania do funkcji tak, jak potrzebujesz, zgodnie z regułami Swift 2.2+ dotyczącymi nazewnictwa typów funkcji .(Jest to w rzeczywistości ulepszenie w stosunku do
@selector()
dyrektywy ObjC , ponieważ-Wundeclared-selector
sprawdzenie kompilatora weryfikuje tylko, że istnieje nazwany selektor. Przekazywana funkcja Swift służy do#selector
sprawdzania istnienia, członkostwa w klasie i podpisu typu).Istnieje kilka dodatkowych zastrzeżeń dotyczących odwołań funkcji przekazywanych do
#selector
wyrażenia:insertSubview(_:at:)
VsinsertSubview(_:aboveSubview:)
). Ale jeśli funkcja nie posiada parametrów, jedynym sposobem, aby go disambiguate jest użycieas
obsady z podpisem typu funkcja (npfoo as () -> ()
vsfoo(_:)
).var foo: Int
, możesz użyć#selector(getter: MyClass.foo)
lub#selector(setter: MyClass.foo)
.Ogólne notatki:
Przypadki, w których
#selector
nie działa i nazywanie: Czasami nie ma odwołania do funkcji, za pomocą którego można by wybrać selektor (na przykład metodami dynamicznie rejestrowanymi w środowisku wykonawczym ObjC). W takim przypadku możesz skonstruowaćSelector
ciąg znaków: np.Selector("dynamicMethod:")
- tracisz sprawdzanie poprawności kompilatora. Kiedy to zrobisz, musisz przestrzegać reguł nazewnictwa ObjC, w tym dwukropków (:
) dla każdego parametru.Dostępność selektora: Metoda, do której odwołuje się selektor, musi być dostępna w środowisku wykonawczym ObjC. W Swift 4 każda metoda narażona na ObjC musi mieć poprzednią deklarację z
@objc
atrybutem. (W poprzednich wersjach posiadałeś ten atrybut w niektórych przypadkach za darmo, ale teraz musisz go wyraźnie zadeklarować).Pamiętaj, że
private
symbole również nie są narażone na środowisko uruchomieniowe - twoja metoda musi mieć przynajmniejinternal
widoczność.Kluczowe ścieżki: Są one powiązane, ale niekoniecznie takie same jak selektory. Istnieje również specjalna składnia dla nich w Swift 3: np
chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Szczegóły patrz SE-0062 . I jeszcze więcejKeyPath
rzeczy w Swift 4 , więc upewnij się, że używasz właściwego interfejsu API opartego na KeyPath zamiast selektorów, jeśli to konieczne.Możesz przeczytać więcej o selektorach w części Interakcja z interfejsami API Objective-C w Korzystanie z Swift z kakao i Objective-C .
Uwaga: Przed wersją Swift 2.2,
Selector
zgodnyStringLiteralConvertible
, więc możesz znaleźć stary kod, w którym puste interfejsy są przekazywane do interfejsów API, które pobierają selektory. Będziesz chciał uruchomić „Konwertuj na bieżącą składnię szybkiego” w Xcode, aby uzyskać dostęp do tych#selector
.źródło
size:andShape:
, jeśli pierwszy argument jest nazwany może być potrzebnyWith
, czyliinitWithData:
zafunc init(Data data: NSData)
Oto szybki przykład korzystania z
Selector
klasy w Swift:Pamiętaj, że jeśli metoda przekazana jako ciąg znaków nie działa, zakończy się niepowodzeniem w czasie wykonywania, nie skompiluje czasu i zawiesi aplikację. Bądź ostrożny
źródło
@selector
jest przydatny, ale nie jest egzekwowany tak formalnie, jak mogłoby się wydawać. „Niezadeklarowany selektor” jest jedynie ostrzeżeniem kompilatora, ponieważ nowe selektory można zawsze wprowadzić w czasie wykonywania. Jednak weryfikowalne / refaktoryzowalne odniesienia selektora w Swift byłyby dobrym żądaniem funkcji .Ponadto, jeśli twoja (Swift) klasa nie pochodzi od klasy Objective-C, musisz mieć dwukropek na końcu ciągu nazwy metody docelowej i musisz użyć właściwości @objc z metodą docelową, np.
w przeciwnym razie pojawi się błąd „Unrecognized Selector” w czasie wykonywania.
źródło
Selector
słowo kluczowe nie jest obowiązkowe. Więc w tym przypadku podpis musi być@objc func method(timer: NSTimer) {/*code*/}
@objc
pracował dla mnie. Nie musiałem zawieraćtimer: NSTimer
w metodzie podpisu, aby można go było wywołać.Aktualizacja Swift 2.2+ i Swift 3
Użyj nowego
#selector
wyrażenia, które eliminuje potrzebę używania literałów łańcuchowych, dzięki czemu użycie jest mniej podatne na błędy. Na przykład:staje się
Zobacz także: Propozycja szybkiej ewolucji
Uwaga (Swift 4.0):
Jeśli używasz
#selector
, musisz zaznaczyć funkcję jako@objc
Przykład:
@objc func something(_ sender: UIButton)
źródło
Swift 4.0
tworzysz Selektor jak poniżej.
1. dodaj wydarzenie do przycisku takiego jak:
a funkcja będzie jak poniżej:
źródło
@objc
przedfunc
która jest wymagana w Swift 4.Dla przyszłych czytelników odkryłem, że napotkałem problem i dostaję
unrecognised selector sent to instance
błąd, który został spowodowany przez oznaczenie celufunc
jako prywatnego.func
Muszą być dostępne publicznie być wywołana przez obiekt z odniesieniem do selektora.źródło
objc
ją przed deklaracją. Np .:@objc private func foo() { ...
wtedy możesz użyć"foo"
jako selektora, ile chceszinternal
, dlatego nie określa żadnego modyfikatora dostępu. Często używam tego wzoru://MARK: - Selector Methods\n extension MyController {\n func buttonPressed(_ button: UIButton) {
Na wypadek, gdyby ktoś miał ten sam problem, który miałem z NSTimer, gdzie żadna z pozostałych odpowiedzi nie rozwiązała tego problemu, naprawdę ważne jest, aby wspomnieć, że jeśli używasz klasy, która nie dziedziczy po NSObject bezpośrednio lub głęboko w hierarchii ( np. ręcznie tworzone szybkie pliki), żadna z pozostałych odpowiedzi nie będzie działać, nawet jeśli zostanie określona w następujący sposób:
Nie zmieniając niczego innego niż tylko dziedziczenie klasy od NSObject, przestałem otrzymywać błąd „Nierozpoznany selektor” i logika działała zgodnie z oczekiwaniami.
źródło
Jeśli chcesz przekazać parametr do funkcji z NSTimer, oto twoje rozwiązanie:
Umieść dwukropek w tekście selektora (tester :), a parametry wejdź w userInfo.
Twoja funkcja powinna przyjmować NSTimer jako parametr. Następnie wystarczy wyodrębnić userInfo, aby uzyskać parametr, który przeszedł.
źródło
scheduledTimerWith...
automatycznie dodaje je do bieżącej runloop - więc nie ma dziwne zachowanie tutaj w ogóle;)Selektory są wewnętrzną reprezentacją nazwy metody w Objective-C. W Objective-C „@selector (methodName)” konwertuje metodę kodu źródłowego na typ danych SEL. Ponieważ nie możesz użyć składni @selector w Swift (Rickster jest na miejscu), musisz ręcznie określić nazwę metody jako obiekt String lub przekazując obiekt String do typu Selector. Oto przykład:
lub
źródło
Swift 4.1
Z próbką gestu stuknięcia
Więcej informacji na temat: wyrażenie selektora znajduje się w dokumencie Apple
źródło
źródło
// Odśwież metodę kontroli
źródło
Ponieważ opublikowano Swift 3.0, jeszcze bardziej subtelne jest zadeklarowanie odpowiedniego parametru targetAction
źródło
Podczas używania
performSelector()
/addtarget()/NStimer.scheduledTimerWithInterval()
metody Twoja metoda (pasująca do selektora) powinna być oznaczona jakoW Swift 2.2 musisz napisać „#selector ()” zamiast łańcucha i nazwy selektora, aby nie było już możliwości wystąpienia błędów ortograficznych i awarii. Poniżej znajduje się przykład
źródło
tworzysz Selektor jak poniżej.
1.
2)
Zauważ, że składnia @selector zniknęła i została zastąpiona prostym ciągiem nazwującym metodę do wywołania. Jest jeden obszar, w którym wszyscy możemy się zgodzić, że gadatliwość przeszkodzi. Oczywiście, jeśli zadeklarujemy, że istnieje metoda docelowa o nazwie flatButtonPressed: lepiej napisz jedną:
ustaw zegar:
Aby być kompletnym, oto flatButtonPressed
źródło
Znalazłem wiele z tych odpowiedzi, które były pomocne, ale nie było jasne, jak to zrobić z czymś, co nie było przyciskiem. Szybko dodawałem rozpoznawanie gestów do UILabel i walczyłem, więc oto, co znalazłem, działało dla mnie po przeczytaniu wszystkiego powyżej:
Gdzie „Selektor” został zadeklarowany jako:
Zauważ, że jest to publiczne i że nie używam składni Selector (), ale można to również zrobić.
źródło
Użycie #selector sprawdzi kod w czasie kompilacji, aby upewnić się, że metoda, którą chcesz wywołać, faktycznie istnieje. Co więcej, jeśli metoda nie istnieje, pojawi się błąd kompilacji: Xcode odmówi zbudowania Twojej aplikacji, tym samym zakazując zapomnienia o innym możliwym źródle błędów.
źródło
Przydatne może być zwrócenie uwagi na to, gdzie skonfigurowano element sterujący, który wyzwala działanie.
Na przykład odkryłem, że podczas konfigurowania UIBarButtonItem musiałem utworzyć przycisk w ramach viewDidLoad, inaczej dostałbym nierozpoznany wyjątek selektora.
źródło
Zmień jako prosty ciąg nazewnictwa w metodzie wywołującej składnię selektora
Następnie wpisz func test ().
źródło
selector
to słowo zeObjective-C
świata i możesz z niego korzystać,Swift
aby mieć możliwość dzwonieniaObjective-C
z niego.Swift
Pozwala na wykonanie kodu w czasie wykonywaniaPrzed
Swift 2.2
składnią jest:Ponieważ nazwa funkcji jest przekazywana
Selector
jako parametr String („foo”), nie można sprawdzić nazwy w czasie kompilacji . W rezultacie ty może dostać błąd wykonania:Po
Swift 2.2+
składni jest:Autouzupełnianie Xcode pomaga ci wybrać odpowiednią metodę
źródło
Dla Swift 3
// Przykładowy kod do utworzenia timera
źródło
Selektor w Swift 4:
źródło
Dla szybkiego 3
Deklaracja funkcji W tej samej klasie:
źródło
self
wyboru w selektorze. To powinno wystarczyć:let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(test), userInfo: nil, repeats: true)