Quando utilizzare @objc in Swift?


87

In Swift, vedo alcuni metodi come:

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

Mi chiedevo, quando usare @objc? Ho letto alcuni documenti, ma dicono che quando vuoi che sia richiamabile in Objective-C, dovresti aggiungere il flag @objc

Tuttavia, questa è una funzione privata in Swift, cosa fa @obj?


1
bella domanda !!!
Erhan Demirci

Risposte:


67

privato significa che è visibile solo in Swift. quindi usa @objc per essere visibile in Objective-C. Se hai una funzione per selezionare una funzione privata in swift, è richiesta.

L'attributo @objc rende la tua API Swift disponibile in Objective-C e nel runtime Objective-C.

Vedi: 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


1
quindi @objc private func doubleTapGestureRecognized, qual è il punto di avere sia @objc che private? Stai dicendo che le classi Objective-C possono sovrascrivere doubleTapGestureRecognized?
Wingzero

1
Immagino, perché in obj-c puoi comunque sovrascrivere qualsiasi metodo.
strangetimes

2
Non sono sicuro di come questa risposta sia giusta e risponda alla sua Q. L'ans fornito qui è già nella sua stessa Q "ma dicono che quando vuoi che sia richiamabile in Objective-C, dovresti aggiungere \ @objc flag", il suo D è "Questa è una funzione privata in swift, cosa fa \ @obj?"
KBJ

3
I collegamenti si interrompono. Soprattutto nella documentazione Apple. Si prega di considerare di estrarre gli elementi chiave dalla documentazione qui.
levigroker

55

Un'altra risposta tardiva, ma nessuna delle risposte esistenti su questa domanda risponde davvero alla domanda dell'OP, che è: perché diamine dovresti usare @objcsu un privatemembro della classe, se @objcè lì per l'interazione con Objective-C e il membro in questione è privato, il che significa che anche se hai codice Objective-C nel tuo progetto, non dovrebbe comunque essere in grado di vedere il membro?

Il motivo è che, poiché molti dei framework sono scritti in Objective-C, a volte sono necessarie funzionalità Objective-C per interagire con determinate API.

Ad esempio, supponiamo che io voglia registrarmi per una notifica tramite DistributedNotificationCenter:

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

Affinché funzioni, dobbiamo essere in grado di ottenere il selettore per il somethingHappenedmetodo. Tuttavia, i selettori sono un concetto Objective-C, quindi se il metodo non è visibile a Objective-C, non dispone di un selettore. Pertanto, anche se il metodo è privato e non deve essere chiamato da codice esterno arbitrario, avrà bisogno di una @objcaffinché il DistributedNotificationcodice, che è scritto in Objective-C, possa chiamarlo tramite il suo selettore.

Un altro caso comune in cui @objcè necessario è supportare KVC (Key-Value Coding), specialmente su macOS, dove KVC e KVO vengono utilizzati per implementare Cocoa Bindings. KVC è, come molti altri sistemi in Cocoa, implementato in Objective-C, che ha l'effetto di richiedere che le proprietà conformi a KVC siano esposte al runtime Objective-C. A volte, ha senso che le proprietà conformi a KVC siano private. Un esempio è quando hai una proprietà che influisce su altre proprietà:

@objc private dynamic var originalProperty: String

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

In questo caso, la nostra proprietà effettivo memorizzato è privata, ma la proprietà dipendente, che noi facciamo esponiamo al codice esterno, ha bisogno di inviare le sue notifiche quando la proprietà privata viene aggiornato. Contrassegnando la proprietà privata come @objc, possiamo farlo facilmente impostando una dipendenza KVC, altrimenti dovremmo scrivere il codice per inviare manualmente le notifiche nella proprietà privata willSete nei didSetgestori. Inoltre, la proprietà statica che informa il sistema KVC da cui dependentPropertydipende originalPropertydeve essere esposta a Objective-C in modo che il sistema KVC lo trovi e lo chiami, ma non è rilevante per i client del nostro codice.

Inoltre, un controller di visualizzazione in un'app macOS che aggiorna i controlli nella sua vista utilizzando Cocoa Bindings come dettaglio di implementazione può rendere alcune proprietà private conformi a KVC per associare tali controlli a loro.

Quindi, come puoi vedere, ci sono momenti in cui un metodo o una proprietà potrebbe dover essere esposto a Objective-C per interagire con i framework, senza necessariamente dover essere visibile ai client del tuo codice.


25

@objc / dynamic

È per compatibilità: una volta importato il file / codice Swift in un progetto basato su Objective-C.

E usalo se vuoi che la tua proprietà / metodo sia accessibile tramite codice o classe Objective-C.

Il più delle volte accade quando stai sottoclassando una classe Swift della classe base Objective-C.

Una classe o un protocollo Swift deve essere contrassegnato con l' attributo @objc per essere accessibile e utilizzabile in Objective-C. Questo attributo dice al compilatore che è possibile accedere a questo pezzo di codice Swift da Objective-C. Se la tua classe Swift è un discendente di una classe Objective-C, il compilatore aggiunge automaticamente l'attributo @objc per te.

Qui la documentazione di Apple che dice di @objc.

Utilizzando Swift da Objective-C

Compatibilità dell'interoperabilità linguistica

Collegamenti aggiornati:
sembra che i collegamenti siano stati aggiornati da Apple.


11

@objc è un attributo di classe, quindi usi

@objc public class MyClass

Espone i metodi della classe alle classi Objective C, quindi lo userai solo se la tua classe contiene funzioni pubbliche


7

Una risposta tardiva, ma questo @objccomportamento sta cambiando leggermente a partire da Swift 4 (che è uscito in Xcode 9, che è stato generalmente rilasciato 10 giorni fa).

In Swift 4, alcuni casi di inferenza di @objcvengono rimossi. Ciò significa solo che in alcuni casi aggiuntivi in ​​cui prima che l' @objcintestazione fosse dedotta dal compilatore Swift, in Swift 4 non era dedotta.

Maggiori informazioni sulla proposta di evoluzione di Swift su questo cambiamento

Come è stato accennato, in generale @objcè esporre alcuni metodi al runtime Objective-C, che fa parte dell'interoperabilità di Swift con il linguaggio.


1
quindi questo dovrebbe essere il motivo per cui dopo l'aggiornamento a Swift 4 alcune variabili non sono accessibili da ObjC, giusto? Con Swift 3.X non era necessario aggiungere@objc
rgkobashi

oh ok, è sempre bene ricontrollare con qualcun altro, grazie!
rgkobashi

1

@objcespone una dichiarazione a Objective-C runtime. Diamo uno sguardo alla #selectorfunzionalità di Swift per utilizzare un runtime Objective-C. In questo caso puoi definire il tuo Swift @objc private func[Altro]

Per utilizzare le funzioni di Swift da Objective-C:

  1. La classe di Swift dovrebbe essere estesa da NSObject
  2. Di Mark Swift:

    un. solo @objcMembers classe - per esporre tutti i public costruttori , campi e metodi . Inoltre è applicabile per le sottoclassi

    b. @objc class / enum / protocol (eccetto struct ) [tipo con nome]

    • @objc class (opzionale) - per esporre un valore predefinito public init() . O @objc(<custom_name>)per impostare un nome personalizzato per la classe.
    • @objc costruttori , campi e metodi - per esporli selettivamente

Il metodo di Swift sarà disponibile dalla prossima denominazione:

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

Per esempio:

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

[ @objce dynamic]

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.