Skip to content

Instantly share code, notes, and snippets.

@SergLam
Last active September 3, 2020 15:57
Show Gist options
  • Save SergLam/3bc0671c3455be24caf3233cddbba513 to your computer and use it in GitHub Desktop.
Save SergLam/3bc0671c3455be24caf3233cddbba513 to your computer and use it in GitHub Desktop.
Singleton - notify many subscribers via weak objects set - inspired by article - https://nshipster.com/nshashtable-and-nsmaptable/
extension SocketClient {
enum Event: String, CaseIterable {
// Chat:
case sendMessage = "speak"
case typing = "typing"
case lastSeen = "last_seen"
case unreadConversations = "unread_conversations"
}
}
import Foundation
import SwiftyJSON
protocol SocketActionObserver: class {
func socketDidReceiveState(_ state: SocketClient.ChannelState, for channel: SocketClient.GChannel)
func socketDidReceiveResponse(for event: SocketClient.Event, data: JSON)
}
extension SocketActionObserver {
func observeSocket(for events: SocketClient.Event...) {
observeSocket(for: events)
}
func observeSocket(for events: [SocketClient.Event]) {
for event in events {
let observers = SocketClient.eventsObservers[event] ?? .init()
observers.insert(self)
SocketClient.eventsObservers[event] = observers
}
}
func stopObservingSocket(for events: SocketClient.Event...) {
for event in events {
guard let observers = SocketClient.eventsObservers[event] else { continue }
observers.remove(self)
SocketClient.eventsObservers[event] = observers
}
}
func stopObservingAllSocketEvents() {
for event in SocketClient.Event.allCases {
guard let observers = SocketClient.eventsObservers[event] else { continue }
observers.remove(self)
SocketClient.eventsObservers[event] = observers
}
}
}
//
extension SocketClient {
/// Socket event observers.
fileprivate static var eventsObservers: [SocketClient.Event: WeakSet<SocketActionObserver>] = [:]
/// Will go through all observers object for given socket event
/// and will call method related to this action.
///
/// - Parameter event: Event about which observers will be notified.
/// - Parameter data: JSON data that came along with the event.
/// - Parameter queue: Operation queue, where the notification will happen.
func notifyObservers(about event: Event, with data: JSON, queue: OperationQueue = .main) {
guard let observers = SocketClient.eventsObservers[event]?.allObjects else { return }
queue.addOperation { observers.forEach { $0.socketDidReceiveResponse(for: event, data: data) } }
}
func notifyObservers(about state: SocketClient.ChannelState, queue: OperationQueue = .main) {
}
}
// Usage:
import Foundation
import SwiftyJSON
class SocketClient {
// MARK: - Singleton
static let shared = SocketClient()
enum State: Int, Comparable {
case unknown = 0 // initial state
case disconnected // connection is not established
case rejected // connection is rejected
case connecting // connecting was started, but not yet finished
case connected // connection is established, but authentication is not confirmed
case authenticating // authentication was started, but not yet finished
case authenticated // connection is established AND authentication is confirmed
public static func < (left: State, right: State) -> Bool { left.rawValue < right.rawValue }
public static func <= (left: State, right: State) -> Bool { left.rawValue <= right.rawValue }
public static func > (left: State, right: State) -> Bool { left.rawValue > right.rawValue }
public static func >= (left: State, right: State) -> Bool { left.rawValue >= right.rawValue }
}
func receiveNewData(_ data: [String: Any]) {
SocketClient.shared.notifyObservers(about: .sendMessage, with: JSON(data))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment