Kiedy używać @objc w Swift?

87

W Swift widzę kilka metod, takich jak:

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

Zastanawiałem się, kiedy używać @objc? Czytałem niektóre dokumenty, ale mówią, że jeśli chcesz, aby było możliwe wywołanie w Objective-C, powinieneś dodać flagę @objc

Jest to jednak funkcja prywatna w języku Swift. Co robi @obj?

Wingzero
źródło
1
Fajne pytanie !!!
Erhan Demirci

Odpowiedzi:

67

prywatny oznacza, że ​​jest widoczny tylko w języku Swift. więc użyj @objc, aby zobaczyć w Objective-C. Jeśli masz funkcję szybkiego wybierania funkcji prywatnej, jest to wymagane.

Atrybut @objc sprawia, że ​​interfejs API Swift jest dostępny w środowisku uruchomieniowym Objective-C i Objective-C.

Zobacz: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html

Reming Hsu
źródło
1
więc po @objc private func doubleTapGestureRecognizedco mieć zarówno @objc, jak i prywatne? Czy mówisz, że klasy Objective-C mogą nadpisywać doubleTapGestureRecognized?
Wingzero
1
Chyba dlatego, że w obj-c i tak możesz nadpisać dowolną metodę.
strangetimes
2
Nie jestem pewien, jak ta odpowiedź jest poprawna i odpowiada na jego pytanie. Odpowiedzi podane tutaj są już w jego Q "ale mówią, że jeśli chcesz, aby było wywoływalne w Objective-C, powinieneś dodać \ @objc flag", jego główne Pytanie brzmi: „To jest funkcja prywatna w szybkim, co robi \ @obj?”
KBJ
3
Łamane linki. Szczególnie w dokumentacji Apple. Rozważ wyodrębnienie kluczowych elementów z dokumentacji tutaj.
levigroker
55

Kolejna późna odpowiedź, ale żadna z istniejących odpowiedzi na to pytanie tak naprawdę nie odpowiada na pytanie PO, a mianowicie: dlaczego do cholery miałbyś używać @objcna privateczłonku klasy, jeśli @objcistnieje do interakcji z celem-C i tym członkiem jest prywatny, co oznacza, że ​​nawet jeśli masz kod Objective-C w swoim projekcie, i tak nie powinien on widzieć członka?

Powodem jest to, że ponieważ wiele frameworków jest napisanych w Objective-C, czasami funkcje Objective-C są potrzebne do interakcji z niektórymi API.

Na przykład załóżmy, że chcę zarejestrować się w celu otrzymania powiadomienia przez DistributedNotificationCenter:

DistributedNotificationCenter.default.addObserver(self,
                                                  selector: #selector(somethingHappened(_:)),
                                                  name: someNotification,
                                                  object: nil)

Aby to zadziałało, musimy być w stanie uzyskać selektor dla somethingHappened metody. Jednak selektory są koncepcją Objective-C, więc jeśli metoda nie jest widoczna dla Objective-C, nie ma selektora. Dlatego, nawet jeśli metoda jest prywatna i nie powinna być wywoływana przez dowolnego kodu z zewnątrz, to będzie potrzebować @objc, aby dla DistributedNotificationkodu, który jest napisany w Objective-C, aby móc nazwać go za pomocą selektora.

Innym częstym przypadkiem, w którym @objcjest to potrzebne, jest obsługa kodowania klucz-wartość (KVC), szczególnie w systemie macOS, gdzie KVC i KVO są używane do implementacji powiązań kakao. KVC, podobnie jak wiele innych systemów w kakao, jest zaimplementowane w Objective-C, co powoduje, że właściwości zgodne z KVC muszą być widoczne w środowisku wykonawczym Objective-C. Czasami ma sens, aby właściwości zgodne z KVC były prywatne. Jednym z przykładów jest sytuacja, gdy masz właściwość, która wpływa na inne właściwości:

@objc private dynamic var originalProperty: String

@objc private static let keyPathsForValuesAffectingDependentProperty: Set<String> = [
    #keyPath(originalProperty)
]
@objc public var dependentProperty: String { return changeItSomehow(self.originalProperty) }

W tym przypadku nasz rzeczywisty majątek przechowywany jest prywatny, ale własnością zależne, które nie narazić się do kodu zewnętrznego, musi wysłać swoje powiadomienia, gdy prywatna własność jest aktualizowana. Oznaczając własność prywatną jako @objc, możemy to łatwo zrobić, konfigurując zależność KVC - w przeciwnym razie musielibyśmy napisać kod, aby ręcznie wysyłać powiadomienia w właściwościach prywatnych willSeti didSetprogramach obsługi. Ponadto właściwość statyczna, która informuje system KVC, od którego dependentPropertyjest zależny, originalPropertymusi być ujawniona Objective-C, aby system KVC i go znaleźć i wywołać, ale nie jest to istotne dla klientów naszego kodu.

Ponadto kontroler widoku w aplikacji macOS, który aktualizuje formanty w swoim widoku przy użyciu powiązań Cocoa jako szczegółów implementacji, może sprawić, że niektóre właściwości prywatne będą zgodne z KVC w celu powiązania z nimi tych formantów.

Jak widać, są chwile, kiedy metoda lub właściwość może wymagać ujawnienia Objective-C w celu interakcji z platformami, bez konieczności bycia widoczną dla klientów kodu.

Charles Srstka
źródło
25

@objc / dynamic

Chodzi o kompatybilność: po zaimportowaniu pliku / kodu Swift do projektu opartego na Objective-C.

I użyj tego, jeśli chcesz, aby Twoja właściwość / metoda była dostępna za pomocą kodu lub klasy Objective-C.

W większości przypadków dzieje się tak, gdy tworzysz podklasę klasy Swift klasy bazowej Objective-C.

Klasa lub protokół Swift musi być oznaczony atrybutem @objc, aby był dostępny i użyteczny w Objective-C. Ten atrybut informuje kompilator, że do tego fragmentu kodu Swift można uzyskać dostęp z poziomu Objective-C. Jeśli Twoja klasa Swift jest potomkiem klasy Objective-C, kompilator automatycznie dodaje atrybut @objc.

Tutaj dokumentacja Apple, która mówi o @objc.

Używanie Swift z Objective-C

Zgodność z językami

Zaktualizowano linki:
Wygląda na to, że linki zostały zaktualizowane przez firmę Apple.

0yeoj
źródło
11

@objc jest atrybutem klasy, więc używasz

@objc public class MyClass

Udostępnia metody klasy klasom Objective C, więc będziesz go używać tylko wtedy, gdy twoja klasa zawiera funkcje publiczne

Fraser
źródło
7

Późna odpowiedź, ale to @objczachowanie zmienia się nieznacznie od wersji Swift 4 (która pojawiła się w Xcode 9, która została ogólnie wydana 10 dni temu).

W Swift 4 @objcusunięto niektóre przypadki wnioskowania . Oznacza to po prostu w niektórych dodatkowych przypadkach, gdy przed @objcwywnioskowaniem nagłówka przez kompilator Swift, w Swift 4 nie został on wywnioskowany.

Przeczytaj więcej na temat propozycji ewolucji Swift na temat tej zmiany

Jak już wspomniano, generalnie @objcpolega na udostępnieniu pewnych metod środowisku uruchomieniowemu Objective-C, które jest częścią interoperacyjności języka Swift.

BHendricks
źródło
1
więc to powinno być powodem, dla którego po aktualizacji do Swift 4 niektóre zmienne nie są dostępne z ObjC, prawda? W przypadku Swift 3.X nie było potrzeby dodawania@objc
rgkobashi
och ok, zawsze dobrze jest dwukrotnie sprawdzić u kogoś innego, dzięki!
rgkobashi
1

@objcujawnia deklarację Objective-C runtime. Rzućmy okiem na #selectorfunkcję Swift, aby użyć środowiska uruchomieniowego Objective-C. W takim przypadku możesz zdefiniować Swift @objc private func[Więcej]

Aby użyć funkcji Swift z Objective-C:

  1. Klasa Swifta powinna zostać rozszerzona z NSObject
  2. Marka Swifta:

    za. tylko @objcMembers klasa - aby ujawnić wszystkie public konstruktory , pola i metody . Dotyczy to również podklas

    b. @objc klasa / wyliczenie / protokół (z wyjątkiem struktury ) [nazwany typ]

    • @objc class (opcjonalne) - aby ujawnić wartość domyślną public init() . Lub @objc(<custom_name>)ustawić własną nazwę dla klasy.
    • @objc konstruktory , pola i metody - aby je selektywnie ujawnić

Metoda Swifta będzie dostępna przy następnym nazewnictwie:

<swiftName>With<firstArgument>:<secondArgument>:

Na przykład:

public func printHelloWorld(arg1: String, arg2:String)
//is reached through: 
[someObject printHelloWorldWithArg1: arg2:];

[ @objci dynamic]

yoAlex5
źródło