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/ astestó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 Selectortyp 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 Selectorpomocą #selectorwyraż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ć #selectorwyraż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-selectorsprawdzenie kompilatora weryfikuje tylko, że istnieje nazwany selektor. Przekazywana funkcja Swift służy do #selectorsprawdzania istnienia, członkostwa w klasie i podpisu typu).
Istnieje kilka dodatkowych zastrzeżeń dotyczących odwołań funkcji przekazywanych do #selectorwyraż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 asobsady 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 #selectornie 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ć Selectorcią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 @objcatrybutem. (W poprzednich wersjach posiadałeś ten atrybut w niektórych przypadkach za darmo, ale teraz musisz go wyraźnie zadeklarować).
Pamiętaj, że privatesymbole również nie są narażone na środowisko uruchomieniowe - twoja metoda musi mieć przynajmniej internalwidoczność.
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 KeyPathrzeczy 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, SelectorzgodnyStringLiteralConvertible , 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łatesti przekaże wartośćselectorargumentu do argumentu.