Próbuję przekonwertować kod źródłowy mojego projektu ze Swift 3 na Swift 4. Jedno ostrzeżenie, które daje mi Xcode, dotyczy moich selektorów.
Na przykład dodaję cel do przycisku za pomocą zwykłego selektora, takiego jak ten:
button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)
To jest ostrzeżenie, które pokazuje:
Argument „#selector” odnosi się do metody instancji „myAction ()” w „ViewController”, która zależy od wnioskowania o atrybucie „@objc”, które jest przestarzałe w Swift 4
Dodaj „@objc”, aby uwidocznić tę metodę wystąpienia w Objective-C
Teraz kliknięcie Fix
na komunikat o błędzie robi to dla mojej funkcji:
// before
func myAction() { /* ... */ }
// after
@objc func myAction() { /* ... */ }
Naprawdę nie chcę zmieniać nazw wszystkich moich funkcji, aby zawierały @objc
znak i zakładam, że nie jest to konieczne.
Jak przepisać selektor, aby poradzić sobie z wycofaniem?
Powiązane pytanie:
@objc
jest już konieczne, aby wystawiać na działanie obj-C, a zatem użycia z przełączników.@objc
? To trochę denerwujące, ale generalnie ustawiam te funkcje jako prywatne, wymagając ode mnie oznaczenia ich jako@objc
tak czy inaczej.@objcMembers
w celu wystawienia wszystkich członków zgodnych z Obj-C na działanie Obj-C, ale nie radziłbym tego, chyba że faktycznie potrzebujesz całej swojej klasy do ujawnienia.Odpowiedzi:
Poprawka jest poprawna - nie ma nic w selektorze, który możesz zmienić, aby metoda, do której się odnosi, była ujawniona w celu-C.
Cały powód tego ostrzeżenia w pierwszej kolejności wynika z SE-0160 . Przed Swift 4
internal
lub nowszymNSObject
składowe klas dziedziczących zgodne z Objective-C były wywnioskowane,@objc
a tym samym narażone na Objective-C, dzięki czemu można je wywoływać za pomocą selektorów (ponieważ środowisko uruchomieniowe Obj-C jest wymagane do wyszukania metody implementacja dla danego selektora).Jednak w Swift 4 już tak nie jest. Obecnie tylko bardzo specyficzne deklaracje są wywnioskowane jako
@objc
na przykład przesłonięcia@objc
metod, implementacje@objc
wymagań protokołu i deklaracje z atrybutami, które implikują@objc
, takie jak@IBOutlet
.Motywacją do tego, jak opisano szczegółowo w powyższej połączonej propozycji , jest po pierwsze zapobieganie
NSObject
kolizji przeciążeń metod w dziedziczeniu klas ze względu na posiadanie identycznych selektorów. Po drugie, pomaga zmniejszyć rozmiar binarny, ponieważ nie musi generować zwrotów dla członków, którzy nie muszą być narażeni na Obj-C, a po trzecie poprawia prędkość dynamicznego łączenia.Jeśli chcesz wystawić członka na Obj-C, musisz oznaczyć go jako
@objc
na przykład:class ViewController: UIViewController { @IBOutlet weak var button: UIButton! override func viewDidLoad() { super.viewDidLoad() button.addTarget(self, action: #selector(foo), for: .touchUpInside) } @objc func foo() { // ... } }
(migrator powinien to zrobić automatycznie z selektorami, gdy jest uruchomiony z wybraną opcją „minimalizuj wnioskowanie”)
Aby wystawić grupę członków na Obj-C, możesz użyć
@objc extension
:@objc extension ViewController { // both exposed to Obj-C func foo() {} func bar() {} }
Spowoduje to ujawnienie wszystkich zdefiniowanych w nim elementów członkowskich Obj-C i spowoduje wyświetlenie błędu w przypadku wszystkich elementów członkowskich, których nie można ujawnić Obj-C (chyba że wyraźnie oznaczono jako
@nonobjc
).Jeśli masz klasę, w której chcesz, aby wszyscy członkowie zgodni z Obj-C byli narażeni na działanie Obj-C, możesz oznaczyć klasę jako
@objcMembers
:@objcMembers class ViewController: UIViewController { // ... }
Teraz wszyscy członkowie, o których można wywnioskować,
@objc
że są. Jednak nie radziłbym tego robić, chyba że naprawdę potrzebujesz wszystkich członków narażonych na Obj-C, biorąc pod uwagę wyżej wymienione wady niepotrzebnego ujawniania członków.źródło
@IBAction
też są automatycznie@objc
? tak nie było do tej pory, ale byłoby to logiczne. EDYCJA: nvm, propozycja jasno stwierdza, że@IBAction
wystarczy, aby metoda była@objc
.Jako oficjalna dokumentacja Apple . musisz użyć @objc, aby wywołać metodę selektora.
źródło
Od, myślę, że Swift 4.2, wszystko, co musisz zrobić, to przypisać @IBAction do swojej metody i możesz uniknąć tej głupiej adnotacji @objc
`` ''
let tap = UITapGestureRecognizer(target: self, action: #selector(self.cancel)) @IBAction func cancel() { self.dismiss(animated: true, completion: nil) }
źródło
Jak już wspomniano w innych odpowiedziach, nie ma sposobu, aby uniknąć
@objc
adnotacji dla selektorów.Ale ostrzeżenie wspomniane w PO można wyciszyć, wykonując następujące kroki:
Off
poniżej znajduje się zrzut ekranu, który ilustruje powyższe kroki:
Mam nadzieję że to pomoże
źródło
Jeśli potrzebujesz obiektywnych członków c w kontrolerze widoku, po prostu dodaj @objcMembers w górnej części kontrolera widoku. Możesz tego uniknąć, dodając IBAction do swojego kodu.
@IBAction func buttonAction() { }
Upewnij się, że podłączasz to gniazdko w scenorysie.
źródło