Skip to content

Instantly share code, notes, and snippets.

@gokselkoksal
Last active September 16, 2022 03:53
Show Gist options
  • Star 39 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save gokselkoksal/97d6ecef610d60d964a660900b1b2e14 to your computer and use it in GitHub Desktop.
Save gokselkoksal/97d6ecef610d60d964a660900b1b2e14 to your computer and use it in GitHub Desktop.
Channel implementation
public class Channel<Value> {
private class Subscription {
weak var object: AnyObject?
private let notifyBlock: (Value) -> Void
private let queue: DispatchQueue
var isValid: Bool {
return object != nil
}
init(object: AnyObject?, queue: DispatchQueue, notifyBlock: @escaping (Value) -> Void) {
self.object = object
self.queue = queue
self.notifyBlock = notifyBlock
}
func notify(_ value: Value) {
queue.async { [weak self] in
guard let strongSelf = self, strongSelf.isValid else { return }
strongSelf.notifyBlock(value)
}
}
}
private var subscriptions: Protected<[Subscription]> = Protected([])
public init() { }
public func subscribe(_ object: AnyObject?, queue: DispatchQueue = .main, notifyBlock: @escaping (Value) -> Void) {
let subscription = Subscription(object: object, queue: queue, notifyBlock: notifyBlock)
subscriptions.write { subscriptions in
subscriptions.append(subscription)
}
}
public func unsubscribe(_ object: AnyObject?) {
subscriptions.write { list in
if let foundIndex = list.index(where: { $0.object === object }) {
list.remove(at: foundIndex)
}
}
}
public func broadcast(_ value: Value) {
subscriptions.write { list in
list = list.filter({ $0.isValid })
list.forEach({ $0.notify(value) })
}
}
}
public class Protected<Value> {
private var queue = DispatchQueue(label: "me.gk.Lightning.Protected", attributes: .concurrent)
private var _value: Value
public var value: Value {
get {
return queue.sync {
return _value
}
}
set {
queue.async(flags: .barrier) { [weak self] in
self?._value = newValue
}
}
}
public init(_ value: Value) {
_value = value
}
public func read(_ block: (Value) -> Void) {
queue.sync {
block(_value)
}
}
public func write(_ block: @escaping (inout Value) -> Void) {
queue.async(flags: .barrier) { [weak self] in
guard let strongSelf = self else { return }
block(&strongSelf._value)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment