9

Il Swift documentation dice il seguente circa protocolli:: Perché @ObjC è necessario per il controllo di conformità e i requisiti facoltativi?

È possibile verificare la conformità del protocollo solo se il protocollo è contrassegnato con l'attributo @objc, come si è visto per il protocollo HasArea sopra. Questo attributo indica che il protocollo deve essere esposto al codice Objective-C ed è descritto in Uso di Swift con Cocoa e Objective-C. Anche se non si interagisce con Objective-C, è necessario contrassegnare i protocolli con l'attributo @objc se si desidera poter verificare la conformità del protocollo .

Si noti inoltre che i protocolli @objc possono essere adottati solo dalle classi e non da da strutture o enumerazioni. Se si contrassegna il protocollo come @objc in per verificare la conformità, sarà possibile applicare il protocollo solo ai tipi di classe.

e

requisiti del protocollo opzionali possono essere specificati solo se il protocollo è contrassegnato con l'attributo @objc. Anche se non si sta interoperando concon Objective-C, è necessario contrassegnare i protocolli con l'attributo @objc se si desidera specificare i requisiti facoltativi.

Si noti inoltre che i protocolli @objc possono essere adottati solo dalle classi e non da da strutture o enumerazioni. Se si contrassegna il protocollo come @objc nell'ordine per specificare i requisiti facoltativi, sarà possibile applicare il protocollo a tipi di classe.


Perché non puri protocolli Swift (non @objc) essere controllati per la conformità. Perché non hanno requisiti opzionali? Qualcuno può indovinare il motivo di progettazione linguistica sottostante?

mi aspetto che a un certo (probabilmente lontano) tempo indeterminato nel futuro di Apple lentamente reimplementare e sostituire cacao e Cocoa Touch con le librerie programmati esclusivamente a Swift. A quel tempo, se non dovessimo evitare l'uso di materiale Obj-C, dovremmo evitare di utilizzare i requisiti del protocollo opzionali e la conformità ai controlli del protocollo nel nostro codice?

Se sì, qual è il modo idiomatico di Swift per ottenere modelli simili senza utilizzare @objc? (. Ad esempio, un delegato con metodi opzionali)


Ad esempio, questo semplice caso d'uso non può essere implementato con @objc protocolli non (e Printable, DebugPrintable e Streamable sono non @objc:

import UIKit 

let firstName = "John" 
let lastName = "Appleseed" 
let age = 33 
let height = 1.74 

let values: [Any] = [firstName, lastName, age, height] 
let stringifiedValues = [String]() 

for value in values 
{ 
    if let pritanbleValue = value as? Printable 
    { 
     stringifiedValues.append(value.description) 
    } 
    else if let debugPrintableValue = value as? DebugPrintable 
    { 
     stringifiedValues.append(value.debugDescription) 
    } 
    else if let streamableValue = value as? Streamable 
    { 
     var string = "" 
     streamableValue.writeTo(&string) 
     stringifiedValues.append(string) 
    } 
    // etc.  
    else 
    { 
     stringifiedValues.append("[NoStringRepresentation]") 
    } 
} 

risposta

11

jckarter, un dipendente di Apple, ha dichiarato quanto segue su un Apple Developer Forums' thread:

Questa è una limitazione del tempo di esecuzione di Swift. Intendiamo rimuovere questa restrizione in una versione futura.

5

Swift probabilmente non include abbastanza informazioni sul tipo di runtime per verificare la conformità del protocollo.I protocolli sono in realtà solo una cosa in fase di compilazione e ObjC include tabelle aggiuntive nel prodotto creato che non sono strettamente necessarie per l'esecuzione del programma per consentire di determinare la conformità. Poiché @objc deve trasformare una classe/protocollo in qualcosa che ObjC comprende, gli oggetti dichiarati con questo attributo ottengono i metadati aggiuntivi e probabilmente altre strutture di dati dell'adattatore in modo che ObjC non si accorga che non sono ObjC reali.

La raccomandazione di Apple in ObjC è sempre stata quella di verificare la presenza di singoli metodi e di non esaminare la classe o il protocollo, per consentire la digitazione anatra e abilitare l'uso di oggetti proxy. La mia ipotesi è che questo sia il motivo per cui i progettisti di Swift sentivano che era giusto escludere i dati di runtime del protocollo nel caso di default, per incoraggiare il corretto rilevamento delle caratteristiche di una classe.

Come utilizzarlo: nel caso di un protocollo, si suppone che utilizzi l'operatore ? (che controlla sia se l'oggetto esiste sia che implementa il metodo specificato). Non so se lo stesso funziona per l'API di sistema, ma dato che è una classe ObjC in quel caso, puoi semplicemente chiamare foo.respondsToSelector("doFoo:").

+0

Grazie per la risposta premurosa! Tuttavia, non sono d'accordo con il secondo paragrafo. Come può un delegatore verificare i singoli metodi del suo delegato a meno che non disponga dei requisiti opzionali del protocollo? Il terzo paragrafo non funziona per me, sto chiedendo del puro codice Swift in un ipotetico codice senza ObjC. Una possibilità che posso pensare è che questa è solo una caratteristica mancante al momento e sarà aggiunta in seguito. –

+0

@ RicardoSánchez-Sáez: In realtà, nessun APA Cocoa verifica mai la conformità del protocollo; controllano sempre che l'oggetto risponda al particolare selettore inviato. È facile farlo in Objective-C. In Swift, devi solo lanciarlo su 'AnyObject' per poter usare il concatenamento opzionale o testare il metodo opzionale. (Naturalmente, se non sei sicuro che l'oggetto sia un'istanza del protocollo, probabilmente è già 'AnyObject'.) – newacct

+0

Hai ragione, forse il pattern delegato non era un buon esempio. Tuttavia, ritengo che il controllo della conformità del protocollo sia ancora utile. Vedere l'esempio che ho aggiunto alla domanda. Non è possibile utilizzare il concatenamento opzionale per metodi sconosciuti su AnyObject senza utilizzare selettori (ei selettori non hanno posto in puro Swift). –