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 zamiast respondsToSelector:
i używaj zamknięć gdziekolwiek możesz zamiast performSelector:
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 ObjC SEL
.)
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 .
let timer = Timer(timeInterval: 1, target: object,
selector: #selector(MyClass.test),
userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
with: button, with: otherButton)
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:
- Wiele funkcji o tej samej nazwie podstawowej można rozróżnić na podstawie ich etykiet parametrów, stosując wyżej wspomnianą składnię dla odniesień do funkcji (np.
insertSubview(_:at:)
Vs insertSubview(_:aboveSubview:)
). Ale jeśli funkcja nie posiada parametrów, jedynym sposobem, aby go disambiguate jest użycie as
obsady z podpisem typu funkcja (np foo as () -> ()
vs foo(_:)
).
- W Swift 3.0+ dostępna jest specjalna składnia dla par getter / setter. Na przykład, biorąc pod uwagę a
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ć przynajmniej internal
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ęcej KeyPath
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
.
selector: test()
wywołatest
i przekaże wartośćselector
argumentu do argumentu.