2016-03-13 17 views
0

我真的很喜歡Sulthan的回答(在Anonymous class in swift) 它描述了建立一個符合協議,但其類隱藏在閉包中的對象。這將是很好的建設單身人士,並沒有污染的名稱空間與類像Recorder1,Recorder2 ...爲什麼不能關閉實例成員

然而,當我嘗試做任何有用的事情,我失敗了,因爲封閉不會關閉外類內部類的實例成員。

protocol EventListener { 
    func handleEvent(event: Int) ->() 
} 

class Recorder { 
    static var events = [Int]() // static is forced 
    var listener: EventListener = { 
     class R : EventListener { 
      func handleEvent(event: Int) { 
       events.append(event) 
       print("Recorded: \(event)") 
      } 
     }// 
     return R() 
    }() 
}// Recorder 

class Distributor { 
    var listeners = [EventListener]() 
    func register(listener: EventListener){ 
     listeners.append(listener) 
    } 
    func distribute(event: Int){ 
     for listener in listeners { 
      listener.handleEvent(event) 
     } 
    } 
} 

var d = Distributor() 
var r1 = Recorder() 
var r2 = Recorder() 

d.register(r1.listener) 
d.register(r2.listener) 
d.distribute(10) 

print(Recorder.events) // [10, 10] Same event recorded twice. 

以上編譯和運行。但我希望 Recorder成爲一個實例成員,以便每個記錄器都有自己的記錄。刪除static會拋出編譯器錯誤:實例成員'events'不能使用

我試着在Recorder中爲handleEvent(event)定義一個實例func record(event)來調用,但是我得到了同樣的錯誤。

Marius的回答(在Instance member cannot be used on type | Closures)建議你不能在定義屬性的時候訪問實例成員,所以我也試圖在後面計算這個監聽器。

class Recorder { 
    var events = [Int]() 
    var listener: EventListener { 
     class R : EventListener { 
      func handleEvent(event: Int) { 
       events.append(event) // error: can't access events 
       print("Recorded: \(event)") 
      } 
     } 
     return R() 
    } 
}// Recorder 

但是編譯器說,它無法訪問的外自我

如果他們無法訪問外部自我,閉包看起來很無能。在Java中,你可以使用類似Recorder.self.events的東西來獲得外部自我。而Recorder.self.可能只有當有名稱衝突時才需要(?)

斯威夫特是這樣設計的還是我錯過了什麼?

你會如何編寫它,所以RecorderDistributor一個對象,除了接收handleEvent消息什麼都不能做?

非常感謝。

回答

1

我不相信有一種方法可以在部分初始化的記錄器中關閉事件。但是,您可以爲記錄器創建兩個階段的初始化過程。第一階段使用默認的空偵聽器創建Recorder對象。第二階段創建一個適當的關閉事件並將其分配給偵聽器。

該實現沒有EventListener協議。我相信有一個簡單的方法可以做到這一點,但對於嵌套類似乎是矯枉過正。因此,而不是包含包含閉包的對象數組的分發服務器。我們正在讓分銷商直接包含關閉數組。

除了額外致電initialize,您的API不會更改。

typealias EventListener = (Int) ->() 

class Distributor { 
    var listeners = [EventListener]() 
    func register(listener: EventListener){ 
    listeners.append(listener) 
    } 
    func distribute(event: Int){ 
    for listener in listeners { 
     listener(event) 
    } 
    } 
} 

class Recorder { 
    var events = [Int]() 
    var listener: EventListener = { 
    (event: Int) in 
    fatalError("Listener not initialized") 
    } 
    func initialize() { 
    listener = { 
     (event: Int) in 
     self.events.append(event) 
     print("Recorded: \(event)") 
    } 
    } 
} 

var d = Distributor() 

// 1st stage of Recorder instantiation 
var r1 = Recorder() 
var r2 = Recorder() 

// 2nd stage 
// r1.listener can now have a closure that includes an init'ed events 
r1.initialize() 
r2.initialize() 

d.register(r1.listener) 
d.register(r2.listener) 
d.distribute(10) 

print(r1.events) 
print(r2.events) 
+0

謝謝你看這個!讓我熬一會兒吧。 – adazacom

0

使用價格Ringo的2階段初始化,並具有錄音機通self到內部類,我已經得到了類隱藏我一直在尋找。它比我希望的稍微冗長一點,但它具有使記錄器實例成員的生命週期清晰的優點。例如,它避免了events周圍的複製vs參考混淆。 self也可以很容易地通過其他方式傳遞數據:adjustment

價格Ringo的解決方案更加優雅,適合這一特定問題。此解決方案更爲通用,可與任何現有協議配合使用。一般來說,我試圖將面向協議的模式整合到我的代碼中。此解決方案創建的對象除符合它們的協議外沒有其他類型。

protocol EventListener { 
    func handleEvent(event: Int) ->() 
} 

class Recorder { 
    var events = [Int]() // example of data out 
    let adjustment: Int // example of data in 
    var listener: EventListener = { 
     class __: EventListener { 
      func handleEvent(event: Int) { } 
     } 
     return __() 
    }() 
    init(adjustment: Int){ 
     self.adjustment = adjustment 
     initializeListener() 
    } 
    private func initializeListener() { 
     listener = { 
      class __: EventListener { 
       unowned var recorder: Recorder 
       init(recorder: Recorder){ 
        self.recorder = recorder 
       } 
       func handleEvent(event: Int) { 
        let adjustedEvent = 
          recorder.adjustment * event 
        recorder.events.append(adjustedEvent) 
       // print("Recorded: \(adjustedEvent)") 
       } 
      } 
      return __(recorder: self) 
     }() 
    } 
}// Recorder 

class Distributor { 
    var listeners = [EventListener]() 
    func addListener(listener: EventListener){ 
     listeners.append(listener) 
    } 
    func distributeEvent(event: Int){ 
     for listener in listeners { 
      listener.handleEvent(event) 
     } 
    } 
} 

var d = Distributor() 
var r1 = Recorder(adjustment: 2) 
var r2 = Recorder(adjustment: 3) 

d.addListener(r1.listener) 
d.addListener(r2.listener) 
d.distributeEvent(10) 

print(r1.events) // [20] 
print(r2.events) // [30] 

如果您還在閱讀,我有一個問題。我已經使實例成員__>recorder無主,以避免保留。我還需要使Recorder>listener無主嗎?

相關問題