Skip to content

Instantly share code, notes, and snippets.

@chosa91
Forked from gokselkoksal/Channel.swift
Last active March 30, 2018 17:56
Show Gist options
  • Save chosa91/e6e02df4a0b745be93752dcfe00fbcf5 to your computer and use it in GitHub Desktop.
Save chosa91/e6e02df4a0b745be93752dcfe00fbcf5 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)
}
}
}
public var recentValue: Any?
public var storeRecentvalue: Bool = false
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) })
}
guard storeRecentvalue else { return }
recentValue = value
}
}
final 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