Skip to content

Commit 341ea3d

Browse files
Merge pull request #327 from pusher/feature/219-220-channel-operations-queue
Enhanced thread safety for common 'PusherChannel' operations
2 parents 570b3e7 + 2cfece4 commit 341ea3d

File tree

2 files changed

+29
-5
lines changed

2 files changed

+29
-5
lines changed

Sources/Models/PusherChannel.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,19 @@ public enum PusherChannelType {
2626

2727
@objcMembers
2828
open class PusherChannel: NSObject {
29-
open var eventHandlers: [String: [EventHandler]] = [:]
29+
// Access via queue for thread safety if user binds/unbinds events to a channel off the main queue
30+
// (Concurrent reads are allowed. Writes using `.barrier` so queue waits for completion before continuing)
31+
private let eventHandlersQueue = DispatchQueue(label: "com.pusher.pusherswift-channel-event-handlers-\(UUID().uuidString)",
32+
attributes: .concurrent)
33+
private var eventHandlersInternal = [String: [EventHandler]]()
34+
open var eventHandlers: [String: [EventHandler]] {
35+
get {
36+
return eventHandlersQueue.sync { eventHandlersInternal }
37+
}
38+
set {
39+
eventHandlersQueue.async(flags: .barrier) { self.eventHandlersInternal = newValue }
40+
}
41+
}
3042
open var subscribed = false
3143
public let name: String
3244
open weak var connection: PusherConnection?
@@ -35,15 +47,15 @@ open class PusherChannel: NSObject {
3547
public var auth: PusherAuth?
3648

3749
// Wrap accesses to the decryption key in a serial queue because it will be accessed from multiple threads
38-
@nonobjc private var decryptionKeyQueue = DispatchQueue(label: "com.pusher.pusherswift-channel-decryption-key-\(UUID().uuidString)")
50+
@nonobjc private var decryptionKeyQueue = DispatchQueue(label: "com.pusher.pusherswift-channel-decryption-key-\(UUID().uuidString)",
51+
attributes: .concurrent)
3952
@nonobjc private var decryptionKeyInternal: String?
4053
@nonobjc internal var decryptionKey: String? {
4154
get {
4255
return decryptionKeyQueue.sync { decryptionKeyInternal }
4356
}
44-
4557
set {
46-
decryptionKeyQueue.sync { decryptionKeyInternal = newValue }
58+
decryptionKeyQueue.async(flags: .barrier) { self.decryptionKeyInternal = newValue }
4759
}
4860
}
4961

Sources/Models/PusherChannels.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,19 @@ import Foundation
22

33
@objcMembers
44
@objc open class PusherChannels: NSObject {
5-
open var channels = [String: PusherChannel]()
5+
// Access via queue for thread safety if user subscribes/unsubscribes to a channel off the main queue
6+
// (Concurrent reads are allowed. Writes using `.barrier` so queue waits for completion before continuing)
7+
private let channelsQueue = DispatchQueue(label: "com.pusher.pusherswift-channels-\(UUID().uuidString)",
8+
attributes: .concurrent)
9+
private var channelsInternal = [String: PusherChannel]()
10+
open var channels: [String: PusherChannel] {
11+
get {
12+
return channelsQueue.sync { channelsInternal }
13+
}
14+
set {
15+
channelsQueue.async(flags: .barrier) { self.channelsInternal = newValue }
16+
}
17+
}
618

719
/**
820
Create a new PusherChannel, which is returned, and add it to the PusherChannels list

0 commit comments

Comments
 (0)