簡體   English   中英

Lazy / inline在Swift中實現協議

[英]Lazy/inline implement a protocol in Swift

我想懶惰/內聯在Swift中實現一個協議。 因此,在實現方面,我將訪問協議范圍之外的變量,

與在Java中實現接口而不聲明類相同:

class MyClass:UIView {
  var someComponent:SomeInnerComponent = SomeInnerComponent();
  var count:Int = 0;

  var a = :SomeProtocol { //<----- IS THIS POSSIBLE, IF YES HOW ?
      func a0() {MyClass.count--}
      func a1() {MyClass.count++}
  } 

  someComponenet.delegate = a;
}

protocol SomeProtocol {
  func a0()
  func a1()
}

編輯----

謝謝我看看這個解決方案,我沒有看到如何訪問父類的變量。 所有示例都顯示了一個Anonymous類,但沒有一個示例正在訪問父變量。

你正在尋找的是一個內部類(不一定是匿名的),在一個范圍內聲明,它允許它訪問MyClass實例的count變量,並采用在不同范圍定義的協議。 現在,Swift有一些這樣的部分,但看起來你不能把它們全部放在一起,就像你可能正在尋找的那樣簡潔。

您可能會考慮聲明一個內部類:

class MyView: UIView {
    let someComponent = SomeInnerComponent() // type SomeInnerComponent is inferred
    var count = 0 // type Int is inferred
    class Helper: SomeProtocol {
        func a0() { count-- } // ERROR
        // ...
    }
    init() {
        someComponent.delegate = Helper()
    }
}

但這不起作用,因為count是隱式self.count ,其中selfHelper實例,而不是“擁有” Helper實例的MyView實例。 並且沒有辦法在Helper的方法中引用MyView實例(或其屬性),因為您也可以在沒有現有MyView實例的情況下構造MyView.Helper() Swift中的內部類(或一般的嵌套類型)僅在詞法范圍內嵌套,而不是存在所有權。 (換句話說,因為你引用了Java:Swift中的所有內部類都像Java中的靜態內部類。沒有非靜態的內部類。)如果這是你想要的一個特性, 那么它可能值得講述蘋果你想要它

你也可以嘗試在MyView.init()聲明Helper - 在Swift中你可以在任何地方嵌套類型定義,包括內部函數或其他類型的方法。 在那里定義,它可以引用MyView的屬性。 但是,現在Helper的類型信息只能在MyView.init()看到,所以當你將它分配給someComponent.delegate (其類型只是SomeProtocol )時,你無法使用它......這會導致崩潰編譯器,甚至。 (這是另一個要報告錯誤 ,但是很難說這個錯誤是否真的“編譯器在有效使用時崩潰”或“代碼錯誤,但編譯器崩潰而不是產生錯誤”。)

我能想出的最接近的解決方案看起來像這樣:

class SomeInnerComponent {
    var delegate: SomeProtocol?
}
protocol SomeProtocol {
    func a0()
    func a1()
}
class MyClass  {
    var someComponent = SomeInnerComponent()
    var count = 0
    struct Helper: SomeProtocol {
        var dec: () -> ()
        var inc: () -> ()
        func a0() { dec() }
        func a1() { inc() }
    }
    init() {
        someComponent.delegate = Helper(
            dec: { self.count -= 1 }, // see note below
            inc: { self.count += 1 }
        )
    }
}

這個怎么運作:

  • Helper是一個內部結構(可以是一個類,但結構更簡單)
  • 它實現了a0a1方法,滿足了SomeProtocol的要求
  • a0a1的實現調用閉包decinc ,它們是Helper結構的存儲屬性(也就是實例變量)
  • 在構造Helper實例時(使用默認的成員初始化器, Helper(dec: (Void -> Void), inc: (Void -> Void))您可以編寫(或以其他方式指定)這些閉包)
  • 因為您可以在初始化Helper時編寫閉包,所以這些閉包可以捕獲您調用初始化程序的變量,包括引用創建HelperMyClass實例的隱式self

你需要a0 / a1dec / inc因為你需要閉包(后者)而不是方法來捕獲封閉狀態。 即使閉包和funcs /方法在很多方面可以互換,也不能通過為方法/ func名稱分配閉包來創建方法/ func實現。 (如果SomeProtocol需要閉包屬性而不是方法,那將是一個不同的故事,但我假設SomeProtocol不是你控制的東西。)

無論如何,這可能是一些你可能並不真正需要的樣板和抽象層,因此可能值得研究構建代碼的其他方法。


注意:我的示例使用了封閉{ self.count -= 1 } ,您可能期望{ self.count-- } 后者不起作用,因為這是一個帶有值的表達式,因此Swift會將其解釋為閉包的返回值的簡寫。 然后它會抱怨你為一個期望a () -> () (又名Void -> Void )閉包的屬性分配了一個() -> Int閉包。 使用-= 1代替解決此問題。

我會采取不同的方法,我知道這是一個非常古老的話題,但以防其他人在這個問題上掙扎:

class MyClass:UIView {
  var someComponent:SomeInnerComponent = SomeInnerComponent();
  var count:Int = 0;

  init(){
    // Assign the delegate or do it somewhere else to your preference:
    someComponenet.delegate = ProtocolImplementation(myClass: self);
  }

  private class ProtocolImplementation: SomeProtocol {
      let selfReference: MyClass          

      init(myClass: MyClass){
         selfReference = myClass
      } 

      public func a0(){
         selfReference.count--
      }

      public func a1(){
          selfReference.count++
      }
  }
}

protocol SomeProtocol {
  func a0()
  func a1()
}

通過遵循這種方法,也可以多次包含相同的協議,假設您的協議支持通用,並且您希望實現它兩次。 如果需要,SomeProtocol <SomeObject>和SomeProtocol <OtherObject>都可以這種方式使用。

親切的問候

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM