Skip to content

Commit a611aee

Browse files
committed
Fix #882. Don't automatically remove sockets from nsps since they might be used again
1 parent 0dff23d commit a611aee

File tree

7 files changed

+67
-12
lines changed

7 files changed

+67
-12
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
- Allow setting `SocketEngineSpec.extraHeaders` after init.
44
- Deprecate `SocketEngineSpec.websocket` in favor of just using the `SocketEngineSpec.polling` property.
55
- Enable bitcode for most platforms.
6+
- Fix [#882](https://github.com/socketio/socket.io-client-swift/issues/882). This adds a new method
7+
`SocketManger.removeSocket(_:)` that should be called if when you no longer wish to use a socket again.
8+
This will cause the engine to no longer keep a strong reference to the socket and no longer track it.
69

710
# v13.0.1
811

Source/SocketIO/Client/SocketIOClient.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,14 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
127127

128128
status = .connecting
129129

130-
manager.connectSocket(self)
130+
joinNamespace()
131+
132+
if manager.status == .connected && nsp == "/" {
133+
// We might not get a connect event for the default nsp, fire immediately
134+
didConnect(toNamespace: nsp)
135+
136+
return
137+
}
131138

132139
guard timeoutAfter != 0 else { return }
133140

@@ -183,7 +190,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
183190
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
184191

185192
leaveNamespace()
186-
didDisconnect(reason: "Disconnect")
187193
}
188194

189195
/// Send an event to the server, with optional data items.
@@ -366,21 +372,15 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
366372
/// Call when you wish to leave a namespace and disconnect this socket.
367373
@objc
368374
open func leaveNamespace() {
369-
guard nsp != "/" else { return }
370-
371-
status = .disconnected
372-
373375
manager?.disconnectSocket(self)
374376
}
375377

376378
/// Joins `nsp`.
377379
@objc
378380
open func joinNamespace() {
379-
guard nsp != "/" else { return }
380-
381381
DefaultSocketLogger.Logger.log("Joining namespace \(nsp)", type: logType)
382382

383-
manager?.engine?.send("0\(nsp)", withData: [])
383+
manager?.connectSocket(self)
384384
}
385385

386386
/// Removes handler(s) for a client event.

Source/SocketIO/Manager/SocketManager.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,6 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
233233
///
234234
/// - parameter socket: The socket to disconnect.
235235
open func disconnectSocket(_ socket: SocketIOClient) {
236-
// Make sure we remove socket from nsps
237-
nsps.removeValue(forKey: socket.nsp)
238-
239236
engine?.send("1\(socket.nsp)", withData: [])
240237
socket.didDisconnect(reason: "Namespace leave")
241238
}
@@ -424,6 +421,18 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
424421
engine?.disconnect(reason: "manual reconnect")
425422
}
426423

424+
/// Removes the socket from the manager's control. One of the disconnect methods should be called before calling this
425+
/// method.
426+
///
427+
/// After calling this method the socket should no longer be considered usable.
428+
///
429+
/// - parameter socket: The socket to remove.
430+
/// - returns: The socket removed, if it was owned by the manager.
431+
@discardableResult
432+
open func removeSocket(_ socket: SocketIOClient) -> SocketIOClient? {
433+
return nsps.removeValue(forKey: socket.nsp)
434+
}
435+
427436
private func tryReconnect(reason: String) {
428437
guard reconnecting else { return }
429438

Source/SocketIO/Manager/SocketManagerSpec.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ public protocol SocketManagerSpec : class, SocketEngineClient {
6363
/// called on.
6464
var handleQueue: DispatchQueue { get set }
6565

66+
/// The sockets in this manager indexed by namespace.
67+
var nsps: [String: SocketIOClient] { get set }
68+
6669
/// If `true`, this manager will try and reconnect on any disconnects.
6770
var reconnects: Bool { get set }
6871

@@ -114,6 +117,14 @@ public protocol SocketManagerSpec : class, SocketEngineClient {
114117
/// This will cause a `disconnect` event to be emitted, as well as an `reconnectAttempt` event.
115118
func reconnect()
116119

120+
/// Removes the socket from the manager's control.
121+
/// After calling this method the socket should no longer be considered usable.
122+
///
123+
/// - parameter socket: The socket to remove.
124+
/// - returns: The socket removed, if it was owned by the manager.
125+
@discardableResult
126+
func removeSocket(_ socket: SocketIOClient) -> SocketIOClient?
127+
117128
/// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager.
118129
///
119130
/// Calling multiple times returns the same socket.

Tests/TestSocketIO/SocketMangerTest.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ class SocketMangerTest : XCTestCase {
8888
XCTAssertEqual(manager.reconnectWait, 5)
8989
}
9090

91+
func testManagerRemovesSocket() {
92+
setUpSockets()
93+
94+
manager.removeSocket(socket)
95+
96+
XCTAssertNil(manager.nsps[socket.nsp])
97+
}
98+
9199
private func setUpSockets() {
92100
socket = manager.testSocket(forNamespace: "/")
93101
socket2 = manager.testSocket(forNamespace: "/swift")

Tests/TestSocketIO/SocketSideEffectTest.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,22 @@ class SocketSideEffectTest: XCTestCase {
250250
waitForExpectations(timeout: 0.8)
251251
}
252252

253+
func testConnectCallsConnectEventImmediatelyIfManagerAlreadyConnected() {
254+
let expect = expectation(description: "The client should call the connect handler")
255+
256+
socket = manager.defaultSocket
257+
258+
socket.setTestStatus(.notConnected)
259+
manager.setTestStatus(.connected)
260+
261+
socket.on(clientEvent: .connect) {data, ack in
262+
expect.fulfill()
263+
}
264+
socket.connect(timeoutAfter: 0.3, withHandler: nil)
265+
266+
waitForExpectations(timeout: 0.8)
267+
}
268+
253269
func testConnectDoesNotTimeOutIfConnected() {
254270
let expect = expectation(description: "The client should not call the timeout function")
255271

Tests/TestSocketIOObjc/ManagerObjectiveCTest.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ - (void)testManagerEmitAll {
106106
[self waitForExpectationsWithTimeout:0.3 handler:nil];
107107
}
108108

109+
- (void)testMangerRemoveSocket {
110+
[self setUpSockets];
111+
112+
[self.manager removeSocket:self.socket];
113+
114+
XCTAssertNil(self.manager.nsps[self.socket.nsp]);
115+
}
116+
109117
- (void)setUpSockets {
110118
self.socket = [self.manager testSocketForNamespace:@"/"];
111119
self.socket2 = [self.manager testSocketForNamespace:@"/swift"];

0 commit comments

Comments
 (0)