Zastosowanie wnioskowania Swift 3 @objc w trybie Swift 4 jest przestarzałe?


485

Krótko mówiąc, podczas korzystania z Xcode 9 Beta napotkałem następujące ostrzeżenie:

Zastosowanie wnioskowania Swift 3 @objc w trybie Swift 4 jest przestarzałe. Proszę rozwiązać przestarzałe ostrzeżenia wnioskowania @objc, przetestować kod z włączonym rejestrowaniem „Używanie przestarzałego wnioskowania @objc” i wyłączyć wnioskowanie Swift 3 @objc. **

Po kilku badaniach wciąż nie mam pojęcia, jak rozwiązać problem. Byłbym bardzo wdzięczny za wszelkie wskazówki, jak rozwiązać ten problem, a także wyjaśnienie, co się dzieje.

Moim celem jest lepsze zrozumienie tego, co dzieje się z moim kodem.


4
Tak naprawdę nie otrzymuję ostrzeżenia, który obiekt go powoduje. Xcode po prostu nie mówi, w której linii znajduje się ten obiekt. Wszelkie porady, jak dowiedzieć się, skąd pochodzi to ostrzeżenie?
olyv

Odpowiedzi:


816

Pozbyłem się tego ostrzeżenia, zmieniając ustawienie kompilacji „Swift 3 @objc Inference” moich celów na „Default”.

Wyłącz wnioskowanie @objc Swift 3 w Xcode9

Z tego artykułu :

Przed wersją Swift 4 kompilator automatycznie udostępnił niektóre deklaracje Swift dla Objective-C . Na przykład, jeśli jedna podklasa z NSObject, kompilator utworzył punkty wejścia Cel-C dla wszystkich metod w takich klasach. Mechanizm nosi nazwę wnioskowania @objc.

W Swift 4 takie automatyczne wnioskowanie @objc jest przestarzałe, ponieważ wygenerowanie wszystkich punktów wejścia do celu C jest kosztowne. Gdy ustawienie „Swift 3 @objc Inference” jest ustawione na „On”, umożliwia działanie starego kodu. Wyświetli jednak ostrzeżenia o wycofaniu, które należy rozwiązać. Zaleca się „naprawienie” tych ostrzeżeń i zmianę ustawienia na „Domyślne” , które jest domyślne dla nowych projektów Swift.

Więcej informacji można znaleźć w tej propozycji Swift .


5
Dziękuję Evgenii. Czy to rozwiązanie długoterminowe?
DaleK,

6
@DaleK tak, tak mi się wydaje. Zgodnie z propozycją Swift, o której wspomniałem w mojej odpowiedzi, wnioskowanie o objc jest przestarzałe. Ustawienie „Swift 3 objc Inference” występuje tylko w projektach migrowanych ze starszych wersji Swift. Jeśli ktoś utworzy nowy projekt, ustawienie nie będzie już obecne, co oznacza, że ​​wnioskowanie objc jest wyłączone. Zaleca się adresowanie wszelkich ostrzeżeń wnioskowania objc i ustawienie na „Off”.
Evgenii,

4
Komunikat informacyjny w XCode sugeruje, że: „Używanie @objcwnioskowania Swift 3 w trybie Swift 4 jest przestarzałe. Proszę rozwiązać przestarzałe @objcostrzeżenia wnioskowania, przetestować kod z @objcwłączonym rejestrowaniem „ Używanie przestarzałego wnioskowania Swift 3 ” i wyłączyć @objcwnioskowanie Swift 3 ”. Masz pomysł, gdzie włączyć wspomniane @objcrejestrowanie wnioskowania Swift 3 ?
courteouselk

4
@courteouselk, zgodnie z propozycją Swift, można ustawić zmienną środowiskową SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT na wartości od 1 do 3, aby zobaczyć wykorzystanie punktów wejścia celu C w dziennikach.
Evgenii,

14
Po prostu dodaj - Musisz to zrobić dla wszystkich tagów kompilacji, nie tylko dla projektu.
Krivvenz

270

- Co to jest @objcwnioskowanie? Co się dzieje?

W Swift 3kompilator dokonuje wyboru @objcw wielu miejscach, więc nie musisz tego robić. Innymi słowy, dodaje to @objcdla Ciebie!

W Swift 4kompilator już tego nie robi (tyle). Musisz teraz dodać @objcwyraźnie.

Domyślnie, jeśli masz projekt w wersji wcześniejszej niż Swift 4, otrzymasz ostrzeżenia o tym. W projekcie Swift 4 wystąpią błędy kompilacji. Jest to kontrolowane poprzez SWIFT_SWIFT3_OBJC_INFERENCEustawienie kompilacji. W projekcie wcześniejszym niż Swift 4 jest to ustawione na On. Poleciłbym ustawić to na Default(lub Off), co jest teraz domyślną opcją w nowym projekcie.

Konwersja wszystkiego zajmie trochę czasu, ale ponieważ jest ona domyślna dla Swift 4, warto to zrobić.

- Jak zatrzymać ostrzeżenia / błędy kompilatora?

Istnieją dwa sposoby konwersji kodu, aby kompilator nie narzekał.

Jednym z nich jest użycie @objckażdej funkcji lub zmiennej, która musi być narażona na środowisko wykonawcze Objective-C:

@objc func foo() {

}

Drugim jest użycie @objcMembersprzez Classdeklarację. Zapewnia to automatyczne dodawanie @objcdo WSZYSTKICH funkcji i zmiennych w klasie. Jest to prosty sposób, ale ma koszt, na przykład może zwiększyć rozmiar aplikacji, ujawniając funkcje, które nie musiały być ujawniane.

@objcMembers class Test {

}

- Co to jest @objci dlaczego jest konieczne?

Jeśli wprowadzisz nowe metody lub zmienne do klasy Swift, oznaczenie ich jako @objcnarażające je na środowisko wykonawcze Objective-C. Jest to konieczne, gdy masz kod Objective-C, który korzysta z klasy Swift lub, jeśli używasz funkcji typu Objective-C, takich jak Selectors. Na przykład wzorzec cel-działanie: button.addTarget(self, action:#selector(didPressButton), for:.touchUpInside)

- Dlaczego nie miałbym oznaczać wszystkiego @objc?

Istnieją negatywy związane z oznaczeniem czegoś jako @objc:

  • Zwiększony rozmiar binarny aplikacji
  • Brak przeciążenia funkcji

Proszę pamiętać, że jest to streszczenie na wysokim poziomie i że jest bardziej skomplikowane niż pisałem. Poleciłbym przeczytać aktualną propozycję, aby uzyskać więcej informacji.

Źródła:


@objcnie oznacza dynamicznej wysyłki, Swift może swobodnie korzystać z wysyłki statycznej lub wirtualnej (i może w rezultacie wykonać inny kod). Słowo dynamickluczowe jest wymagane, aby zmusić Swift do korzystania z dynamicznej wysyłki.
kevin

7
Czy istnieją inne sposoby dodawania akcji do przycisku? Jeśli @objcdeprecjonowane, czego musimy użyć?
Aznix,

5
@Stefan tak, może być sporo do konwersji. Podziel go na etapy. Zostaw SWIFT_SWIFT3_OBJC_INFERENCEo On. Konwertuj na Swift 4. Następnie rozwiąż problem @objc. Aby to uprościć, postępuj zgodnie z podstawowymi zasadami: JEŚLI klasa Swift jest używana w kodzie Objc-C (poprzez nagłówek mostkujący) @objcMembers, w przeciwnym razie użyj dodawania jeden po drugim @objc. Wystarczy użyć wyszukiwania Xcode, aby dowiedzieć się, czy klasa Swift jest wywoływana z dowolnego .mpliku. To powinno uczynić konwersję względnie bezbolesną.
kgaidis,

5
@DaleK należy zaakceptować odpowiedź. Tłumienie ostrzeżeń i sprawianie, aby działały tak, jak były w Swift 3, jest opcją, ale IMHO nie jest najlepsze. Ważne jest, aby zrozumieć, dlaczego @objczmieniono Swift 4, a następnie podjąć decyzję o naprawieniu projektu i pozostawieniu go bez zmian .
derpoliuk

2
Dzięki za to krótkie wyjaśnienie
Schmoudi,

48

Migrator nie może zidentyfikować wszystkich funkcji, które wymagają @objc Wnioskowane argumenty C celu oznaczone jako przestarzałe, aby pomóc Ci je znaleźć
• Twórz ostrzeżenia o przestarzałych metodach
• Komunikaty konsoli podczas uruchamiania przestarzałych informacji

wprowadź opis zdjęcia tutaj


1
Więc co powinienem zrobić z @objc? usunąć to? zostaw to? Już to usunąłem. i mam ostrzeżenia, więc muszę je dodać? że w kroku 3 powinienem to zrobić?
Shial

Dodaj @objc tuż przed func
Hassan Taleb

1
o co chodzi w kroku 3? Możesz dodać kilka opisów :)
Shial

W moim przypadku pojawia się to ostrzeżenie, ale nie jest wskazany żaden kod. Istnieją dwie metody oznaczone jako @objc i wydają się być jedynymi, które tego potrzebują. Zmieniłem go na Domyślny i nadal otrzymuję ostrzeżenia podczas kompilacji.
Maury Markowitz

12

Miałem to ostrzeżenie z ustawieniem „Swift 3 @objc Inference” = „Default”. Potem zdałem sobie sprawę, że zostało to ustawione dla Projektu - nie dla celu. Upewnij się więc, że masz w ustawieniu „Domyślne” ustawienie, aby pozbyć się ostrzeżenia.


Zmarnowałem 20 minut na rozwiązanie problemu, nawet po zmianie na Domyślne w ustawieniach projektu. Wskazałeś dokładnie, że należy to zmienić również w celu.
SkrewWszystko

8

Możesz po prostu przejść do „default” zamiast „ON”. Wydaje się bardziej przywiązany do logiki Apple.

(ale wszystkie pozostałe komentarze dotyczące używania @objpozostają aktualne).


7

Rzeczywiście, pozbędziesz się tych ostrzeżeń, wyłączając Swift 3 @objc Inference. Jednak mogą pojawić się subtelne problemy. Na przykład KVO przestanie działać. Ten kod działał idealnie pod Swift 3:

for (key, value) in jsonDict {
    if self.value(forKey: key) != nil {
        self.setValue(value, forKey: key)
    }
}

Po migracji do Swift 4 i ustawieniu domyślnie „Swift 3 @objc Inference” niektóre funkcje mojego projektu przestały działać . Zajęło mi trochę debugowania i badań, aby znaleźć rozwiązanie tego problemu. Według mojej najlepszej wiedzy, oto opcje:

  • Włącz „Swift 3 @objc Inference” (działa tylko, jeśli migrowałeś istniejący projekt z Swift 3) wprowadź opis zdjęcia tutaj
  • Oznacz odpowiednie metody i właściwości jako @objc wprowadź opis zdjęcia tutaj
  • Ponownie włącz wnioskowanie ObjC dla całej klasy za pomocą @objcMembers wprowadź opis zdjęcia tutaj

Ponowne włączenie wnioskowania @objc pozostawia ostrzeżenia, ale jest to najszybsze rozwiązanie. Pamiętaj, że jest dostępna tylko dla projektów migrowanych z wcześniejszej wersji Swift. Pozostałe dwie opcje są bardziej żmudne i wymagają trochę kopania kodu oraz obszernych testów.

Zobacz także https://github.com/apple/swift-evolution/blob/master/propozycje/0160-objc-inference.md


7

Od czasu do czasu jestem programistą iOS (wkrótce będzie więcej), ale nadal nie mogłem znaleźć ustawienia zgodnie z inną odpowiedzią (ponieważ nie miałem tego elementu pęku kluczy, który pokazuje odpowiedź), więc teraz, gdy go znalazłem, pomyślałem Mogę po prostu dodać tę migawkę z wyróżnionymi lokalizacjami, które trzeba będzie kliknąć i znaleźć.

  1. Zacznij w lewym górnym rogu
  2. Wybierz ikonę folderu projektu
  3. Wybierz nazwę głównego projektu poniżej ikony folderu projektu.
  4. Wybierz Ustawienia kompilacji po prawej stronie.
  5. Wybierz swój projekt w zakładce CELE.
  6. Przewiń bardzo daleko w dół (lub wyszukaj słowo wnioskowanie w polu tekstowym wyszukiwania)

Znalezienie ustawienia


6

Możesz spróbować wykonać „aktualizację kapsuły” i / lub „trzepotanie”

Ustawiłem również to ustawienie w xcode.

Ustawienie interfejsu Objective-C jest następujące:

Ustawienie interfejsu ObjectiveC


2

Wnioskowanie Swift 3 @objc Wykorzystanie wnioskowania Swift 3 @objc w trybie Swift 4 jest przestarzałe. Proszę rozwiązać przestarzałe ostrzeżenia wnioskowania @objc, przetestować kod z włączonym rejestrowaniem „Używanie przestarzałego wnioskowania @objc”, a następnie wyłączyć wnioskowanie, zmieniając ustawienie kompilacji „Swift 3 @objc Wnioskowanie” na „Domyślne” dla „XMLParsingURL” cel.

dotarłem do

  1. Pierwszy krok to ustawienie kompilacji

  2. Wyszukaj w Wnioskowanie ustawień kompilacji

  3. change swift 3 @objc Wnioskowanie Domyślne

wprowadź opis zdjęcia tutaj


1

Wystarczy uruchomić test, czekaj do końca, a następnie przejdź do Kompilacji ustawień, Szukaj w Konstruowaniu ustawień wnioskowania, zmień szybkie 3 @objc Wnioskowanie na (Domyślne). to wszystko, co zrobiłem i działało idealnie.


0

Zastosowanie wnioskowania Swift 3 @objc w trybie Swift 4 jest przestarzałe?

użyj func call @objc

func call(){

foo()

}

@objc func foo() {

}

0

Oprócz tego, co powiedział @wisekiddo, możesz również zmodyfikować ustawienia kompilacji w project.pbxprojpliku, ustawiając Swift 3 @obj Inference na domyślne, tak jak SWIFT_SWIFT3_OBJC_INFERENCE = Default;dla twoich smaków kompilacji (tj. Debugowania i wydania), szczególnie jeśli pochodzisz z innego środowiska oprócz Xcode

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.