2014-10-20 6 views
5

Attualmente sto scrivendo del codice Swift in un progetto che è prevalentemente Objective-C. Nel nostro codice ObjC, abbiamo un'intestazione che dichiara typedef GPUImageOutput<GPUImageInput> MyFilter;. Possiamo quindi dichiarare per es. una @property che può essere solo una sottoclasse GPUImageOutput che implementa GPUImageInput.Qual è l'equivalente di Swift di dichiarare `typedef SomeClass <SomeProtocol> MyType`?

(NOTA: GPUImageOutput e GPUImageInput non sono definiti da me, esse fanno parte del GPUImage library)

Il nostro codice Swift non sembra riconoscere questo, anche se l'intestazione è #imported nel nostro Bridging intestazione. Ho cercato di replicare la dichiarazione Swift, ma nessuno di questi sono sintassi corretta:
typealias MyFilter = GPUImageOutput, GPUImageInput
typealias MyFilter = GPUImageOutput : GPUImageInput

+2

ho chiesto la stessa cosa qui: http://stackoverflow.com/questions/24455327/how-do-i-specify-that-a-non-generic-swift-type-should- conforme al protocollo, per gli stessi motivi –

risposta

2

a Swift 4 si può raggiungere questo obiettivo con il nuovo & segno (Di seguito un esempio di un parametro di conferma per UIViewController e UITableViewDataSource:

func foo(vc: UIViewController & UITableViewDataSource) { 
    // access UIViewController property 
    let view = vc.view 
    // call UITableViewDataSource method 
    let sections = vc.numberOfSectionsInTableView?(tableView) 
} 
1

In Swift, qualcosa come il seguente dovrebbe compiere il proprio compito, ma è diverso rispetto al suo omologo objC:

typealias GPUImageOutput = UIImage 
@objc protocol GPUImageInput { 
    func lotsOfInput() 
} 

class GPUImageOutputWithInput: GPUImageOutput, GPUImageInput 
{ 
    func lotsOfInput() { 
     println("lotsOfInput") 
    } 
} 

// ... 

var someGpuImage = GPUImageOutput() 
var specificGpuImage = GPUImageOutputWithInput() 

for image in [someGpuImage, specificGpuImage] { 
    if let specificImage = image as? GPUImageInput { 
     specificImage.lotsOfInput() 
    } else { 
     println("the less specific type") 
    } 
} 

UPDATE: ora che ho capito dove/perché si dispone di questi tipi ...

GPUImage sembra avere un esempio veloce che fa quello che si vuole, come Swift-ly possibile.

Vedi here:

class FilterOperation<FilterClass: GPUImageOutput where FilterClass: GPUImageInput>: FilterOperationInterface { 
... 

Il type constraint syntax può essere applicato alle funzioni, anche, e con un where clause, che è probabilmente buono come avete intenzione di arrivare direttamente a Swift.

Più ho cercato di capire come portare questo trucchetto objc un po 'comune, più ho capito che era il modo più rapido. Una volta visto l'esempio in GPUImage stesso, ero convinto che fosse almeno la tua risposta. :-)

UPDATE 2: Quindi, oltre l'esempio GPUImage specifica ho linkato sopra che utilizza Swift, più e più penso a questo, sia utilizzando una clausola where a guardia della funzione setter, o utilizzando una proprietà calcolabile per filtrare la funzionalità set sembra l'unico modo per andare.

sono arrivato fino a questa strategia:

import Foundation 

@objc protocol SpecialProtocol { 
    func special() 
} 

class MyClass {} 

class MyClassPlus: MyClass, SpecialProtocol { 
    func special() { 
     println("I'm special") 
    } 
} 

class MyContainer { 
    private var i: MyClass? 

    var test: MyClass? { 
     get { 
      return self.i 
     } 
     set (newValue) { 
      if newValue is SpecialProtocol { 
       self.i = newValue 
      } 
     } 
    } 
} 

var container = MyContainer() 

println("should be nil: \(container.test)") 

container.test = MyClass() 
println("should still be nil: \(container.test)") 

container.test = MyClassPlus() 
println("should be set: \(container.test)") 

(container.test as? MyClassPlus)?.special() 

Uscite:

should be nil: nil 
should still be nil: nil 
should be set: Optional(main.MyClassPlus) 
I'm special 

(Opzionalmente, si potrebbe anche usare precondition(newValue is SpecialProtocol, "newValue did not conform to SpecialProtocol") al posto del controllo is, ma che agirà come un assert() può Arresta l'app in caso di mancata corrispondenza. Dipende dalle tue esigenze.)

La risposta di @ rintaro è buona, ed è un buon esempio di utilizzo di un where clausola come guardia (sia piacevole funzionale, che Swift-ly). Tuttavia, odio solo scrivere una funzione setFoo() quando esistono proprietà computabili. Inoltre, anche l'uso di una proprietà computabile ha odore di codice, dal momento che non sembra possibile applicare un vincolo di tipo generico a set e dobbiamo eseguire il test di conformità del protocollo in linea.

+0

Siamo spiacenti, b ut 'GPUImageOutput' e' GPUImageInput' sono [preesistenti] (https://github.com/BradLarson/GPUImage), quindi non posso semplicemente dichiararli nuovamente in modo obsoleto. Aggiornerà la mia domanda per chiarire! –

+0

Questo era solo un esempio, perché non sapevo quale fosse la tua classe base! La chiave è il protocollo @objc, che consente di rilevare la conformità, tutto qui. – greymouser

+0

... e anche +1 per la domanda: si tratta di un caso molto interessante di differenze Swift v. ObjC. – greymouser

4

Non è possibile dichiarare typealias del genere.

Il meglio che possiamo fare è qualcosa di simile:

class MyClass { 
    private var filter:GPUImageOutput 

    init<FilterType:GPUImageOutput where FilterType:GPUImageInput>(filter:FilterType) { 
     self.filter = filter 
    } 

    func setFilter<FilterType:GPUImageOutput where FilterType:GPUImageInput>(filter:FilterType) { 
     self.filter = filter 
    } 

    func someMethod() { 
     let output = self.filter 
     let input = self.filter as GPUImageInput 
     output.someOutputMethod() 
     input.someInputMethod() 
    } 
} 
+0

Bello! Sì, ecco una risposta simile a una domanda doppia: http://stackoverflow.com/a/24455591/418982 –

-3

È possibile utilizzare typealias parola chiave. Ecco come farlo:

typealias MyNewType = MyExistingType 

Non importa se MyExistingType è protocollo o funzione o enum. Tutto ciò che deve essere un certo tipo. E la parte migliore è che puoi applicare il controllo degli accessi su di esso. Si può dire

private typealias MyNewType = MyExistingType 

che rende MyNewType è accessibile solo il contesto che è definito in.

+0

Questa domanda chiede in particolare come dichiarare un typealias per un oggetto di una classe che implementa il protocollo, non solo uno o l'altro. –

Problemi correlati