2014-10-21 6 views
26

Ich fragte mich, ob ich eine versteckte Adoption eines Protokolls in Swift tun könnte.Adoption des Protokolls in Swift verstecken

In Objective-C würde ich einen privaten Header in der m.-Datei verwenden, um Protokolle auszublenden, die ich nicht nach außen ausgesetzt werden soll. Ist so etwas schnell möglich? Putting ein "private" vor dem Protokoll funktioniert offenbar nicht :)

+0

Nein, das ist nicht möglich. – mattt

+0

hey @matt gibt es eine Erklärung dafür? – eyeballz

+1

Swift verwendet explizite Zugriffssteuerung und nicht implizite Vertraulichkeit durch Schnittstellen-/Implementierungsaufteilung. Was Sie beschreiben, hat in Objective-C kein Analog. Wenn Sie Implementierungsdetails ausblenden möchten, müssen Sie die Kapselung verwenden. – mattt

Antwort

9

Bearbeiten: Gefunden einen einfachen Weg, um es zu verstecken. Zumindest aus der xcode-Schnellhilfe-Information: Setzen Sie die Adoption und die Implementierung einfach in eine Erweiterung Ihrer Klasse und sie wird dort nicht angezeigt.

Ursprüngliche Antwort:

kam ich mit diesem Beispiel auf, durch innere Klassen in Java inspiriert. Hier stellt MyVC nicht dar, dass es UICollectionViewDelegate für interne Zwecke implementiert, während die Delegat-Implementierung Zugriff auf MyVC private Variablen hat.

public class MyVC: UIViewController { 

    private let a = 4 as Int 
    private var hiddenDelegate: HiddenDelegateImpl? 

    public override func viewDidLoad() { 
     super.viewDidLoad() 
     hiddenDelegate = HiddenDelegateImpl(outer: self) 
     innerCollectionView.delegate = hiddenDelegate 
    } 
} 

private class HiddenDelegateImpl: NSObject, UICollectionViewDelegate { 

    private weak var outer: MyVC? 

    init(outer: MyVC) { 
     self.outer = outer 
     super.init() 
    } 

    private func doStuff() -> Int { 
     // can access private variables of outer class 
     return outer?.a 
    } 

    // implement delegate methods here 
} 

Beachten Sie, dass HiddenDelegateImpl auch eine innere Klasse von MyVC sein könnte, wählte ich es aus Gründen der Lesbarkeit außerhalb zu setzen.

Im Gegensatz zu Java müssen Instanzen innerer Klassen eine Instanz der äußeren Klasse existieren. Da dies bei Swift nicht der Fall ist, benötigen wir die Problemumgehung outer.

Es gibt auch this nice example, die sich auf die Implementierung von Delegaten konzentriert.

Bearbeiten: Der Delegate eine Instanzvariable in der äußeren Klasse, um es zu behalten, und der Verweis auf die äußere Klasse schwach, um Retain-Zyklen zu vermeiden.

+2

Gute Frage. Es gibt ein echtes Bedürfnis dafür. Externe Benutzer Ihrer Klasse müssen nicht wissen, welche Protokolle sie intern benötigen. Schade, die Lösung ist so unelegant (ein Problem der Sprache, Sie haben die beste Antwort gegeben, denke ich.) – TJez

+0

Danke für die Wertschätzung :) die Frage wurde zunächst abgelehnt, so dass ich dachte, ich wäre dumm. Aber Sie haben völlig Recht, ich möchte nicht, dass der Benutzer meiner Klasse weiß, dass er 10 verschiedene Protokolle intern implementiert, um seine Arbeit zu erledigen. – eyeballz

+0

Ich denke, ein Grund ist, dass sie sich von Delegierten wegbewegen wollen und wollen, dass Sie Schließungen verwenden .Aber mit all den alten APIs, die herumschweben, ist das einfach nicht möglich – eyeballz

-1

Vielleicht hat sich die Sprache seit der Post geändert, aber es funktioniert für mich. Dies ist ein Beispiel dafür, wo ich einen Initialisierer verstecken wollte, um die Lebensdauer eines Objekts zu steuern und eine Nachbearbeitung durchzuführen. In diesem Fall wollte ich Analysen basierend auf der Konfiguration des Anrufers verfolgen und senden.

private protocol Reportable { 
    init() 
    var people:[String:AnyObject] { get } 
    var track:[String:AnyObject] { get } 
} 


public class Analytics { 

    public final class Alpha: Reportable { 

     var thingOne: String? 
     var thingTwo: String? 

     private init() {} 
     private var people:[String:AnyObject] { return [:] } 
     private var track:[String:AnyObject] { return [:] } 
    } 

    public final class Bravo: Reportable { 

     var thingOne: String? 
     var thingTwo: String? 

     private init() {} 
     private var people:[String:AnyObject] { return [:] } 
     private var track:[String:AnyObject] { return [:] } 
    } 


    public static func alpha(configure:Alpha ->()) { 
     return report(configure) 
    } 

    public static func bravo(configure:Bravo ->()) { 
     return report(configure) 
    } 


    private static func report<T:Reportable>(configure:T ->()) { 
     let event = T() 
     configure(event) 
     Analytics.doSomething() 
    } 


    static func doSomething() { 

    } 
} 

// separate file 
func clientCode() { 

    Analytics.alpha { event in 

     event.track // error 

     event.thingOne = "foo" 
     event.thingTwo = "bar" } 

    Analytics.bravo { event in 
     event.thingOne = "foo" 
     event.thingTwo = "bar" } 

} 
Verwandte Themen