2016-06-07 66 views
7

Nella categoria Objective-C, è possibile introdurre la funzionalità estesa introdotta dai metodi di categoria includendo l'intestazione della categoria nella classe.Estensione rapida per l'istanza della classe selezionata

Sembra che tutte le estensioni Swift vengano automaticamente introdotte senza importazione. Come ottieni la stessa cosa in Swift?

Ad esempio:

extension UIView { 
    // only want certain UIView to have this, not all 
    // similar to Objective-C, where imported category header 
    // will grant the capability to the class 
    func extraCapability() { 

    } 
} 
+0

Intendevi in ​​Objective-C? – Siriss

+0

In Swift - Come posso limitare la visibilità nell'estensione di Swift in modo che solo alcune istanze di classe abbiano la capacità estesa? – Boon

risposta

8

Definire un protocollo che servirà come una selezione, che scendessimo le estensioni dovrebbero essere disponibili o no:

protocol UIViewExtensions { } 

quindi definire un'estensione per il protocollo, ma solo per sottoclassi UIView (viceversa non funzionerà):

extension UIViewExtensions where Self: UIView { 
    func testFunc() -> String { return String(tag) } 
} 

una classe che viene definito per avere il protocollo avrà anche l'estensione:

class A: UIView, UIViewExtensions { }  
A().testFunc() //has the extension 

E se non è definito per avere il protocollo, sarà anche non avere l'estensione:

class B: UIView {}  
B().testFunc() //execution failed: MyPlayground.playground:17:1: error: value of type 'B' has no member 'testFunc' 

UPDATE

Dal protocol extensions don't do class polymorphism, se è necessario sostituire le funzioni, le l'unica cosa che posso pensare è sottoclasse:

class UIViewWithExtensions: UIView { 
    override func canBecomeFocused() -> Bool { return true } 
} 
UIViewWithExtensions().canBecomeFocused() // returns true 

questo potrebbe anche essere c ombreggiato con l'estensione, ma non credo che avrebbe ancora più senso.

+3

+1 Nota che in ObjC tutte le sottoclassi ottengono effettivamente i metodi estesi. È solo che il compilatore non li vede in fase di compilazione e genererà avvisi se si tenta di usarli. Questo è importante perché è abbastanza facile rompere questo tipo di protezione in ObjC, e ci sono molti casi d'uso che ObjC non può raggiungere. Questa risposta non solo è il modo giusto per farlo, ma in realtà fa quello che l'OP significa. * Solo i * tipi assegnati a questa estensione la otterranno e tenterà di usarla nei posti sbagliati genereranno errori, non avvisi. Non chiamerei nemmeno questo un "protocollo di soluzione alternativa". È solo un protocollo. –

+0

C'è un problema con questo approccio. Se testFunc() è un metodo esistente in UIView (ad esempio pointInside: withEvent :), la versione di UIView viene chiamata anche se è definita nell'estensione. L'estensione del protocollo non sembra consentire l'override, come possiamo ottenere invece il metodo sostituito? – Boon

+0

@Boon vedere il mio aggiornamento – Daniel

0

NOTA Accesso privato a Swift si differenzia da un accesso privato nella maggior parte delle altre lingue, come è ambito per il file di origine che racchiude piuttosto che alla dichiarazione racchiude. Ciò significa che un tipo può accedere a qualsiasi entità privata definita nello stesso file sorgente di se stessa, ma un'estensione non può accedere ai membri privati ​​di quel tipo se è definita in un file sorgente separato.

Secondo Apple, here, non sembra possibile rendere private le estensioni in file separati.

È possibile creare un'estensione privata nello stesso file sorgente.

2

È possibile effettuare estensioni privato per una particolare classe aggiungendo privata prima della proroga in questo modo

private extension UIView { 

    func extraCapability() { 

    } 
} 

Ciò significa che può essere utilizzato solo in quella particolare classe. Ma dovrai aggiungerlo a ogni classe che richiede questa estensione. Per quanto ne so non c'è modo di importare l'estensione, come si può in Obj-C

+1

Voglio che l'estensione aggiunga funzionalità ad alcuni UIView, ma non a tutti. Con la categoria ObjC, posso farlo. – Boon

+1

Sfortunatamente il meglio che puoi fare in Swift è aggiungerlo alla parte superiore di una classe in cui le visualizzazioni lo richiedono. In questo modo non sarà disponibile per tutte le visualizzazioni nella tua app, solo nelle classi in cui viene aggiunto in alto. Non è una grande soluzione in quanto significa ripetersi, ma non credo che ci sia un altro modo in Swift. Se c'è una soluzione migliore, mi piacerebbe sentirla – AdamM