From f9d8595a25bf239d78cfec4639558b5888afcde1 Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 29 Sep 2018 15:47:30 +0700 Subject: [PATCH 1/5] add optional write completion handler for emit's --- Source/SocketIO/Client/SocketIOClient.swift | 19 +++++++++--- Source/SocketIO/Engine/SocketEngine.swift | 30 +++++++++++-------- .../Engine/SocketEnginePollable.swift | 20 ++++++++----- Source/SocketIO/Engine/SocketEngineSpec.swift | 9 +++--- .../Engine/SocketEngineWebsocket.swift | 10 ++++--- Source/SocketIO/Manager/SocketManager.swift | 2 +- Source/SocketIO/Util/SocketTypes.swift | 5 +++- Tests/TestSocketIO/SocketMangerTest.swift | 2 +- Tests/TestSocketIO/SocketSideEffectTest.swift | 2 +- Tests/TestSocketIOObjc/SocketObjectiveCTest.m | 14 +++++++++ 10 files changed, 77 insertions(+), 36 deletions(-) diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index 501fe30d..ac7dbff5 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -213,7 +213,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { /// - parameter items: The items to send with this event. May be left out. open func emit(_ event: String, _ items: SocketData...) { do { - try emit(event, with: items.map({ try $0.socketRepresentation() })) + try emit(event, with: items.map({ try $0.socketRepresentation() }), completion: {}) } catch { DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", type: logType) @@ -228,7 +228,17 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { /// - parameter items: The items to send with this event. Send an empty array to send no data. @objc open func emit(_ event: String, with items: [Any]) { - emit([event] + items) + emit([event] + items, completion: {}) + } + + /// Same as emit, but meant for Objective-C + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. Send an empty array to send no data. + /// - parameter completion: Callback called on transport write completion. + @objc + open func emit(_ event: String, with items: [Any], completion: @escaping () -> ()) { + emit([event] + items, completion: completion) } /// Sends a message to the server, requesting an ack. @@ -284,8 +294,9 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { return createOnAck([event] + items) } - func emit(_ data: [Any], ack: Int? = nil, binary: Bool = true, isAck: Bool = false) { + func emit(_ data: [Any], ack: Int? = nil, binary: Bool = true, isAck: Bool = false, completion: (() -> ())? = nil) { guard status == .connected else { + completion?(); handleClientEvent(.error, data: ["Tried emitting when not connected"]) return } @@ -295,7 +306,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { DefaultSocketLogger.Logger.log("Emitting: \(str), Ack: \(isAck)", type: logType) - manager?.engine?.send(str, withData: packet.binary) + manager?.engine?.send(str, withData: packet.binary, completion: completion) } /// Call when you wish to tell the server that you've received the event for `ack`. diff --git a/Source/SocketIO/Engine/SocketEngine.swift b/Source/SocketIO/Engine/SocketEngine.swift index 738bf30a..70bea00c 100644 --- a/Source/SocketIO/Engine/SocketEngine.swift +++ b/Source/SocketIO/Engine/SocketEngine.swift @@ -49,7 +49,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So /// A queue of engine.io messages waiting for POSTing /// /// **You should not touch this directly** - public var postWait = [String]() + public var postWait = [Post]() /// `true` if there is an outstanding poll. Trying to poll before the first is done will cause socket.io to /// disconnect us. @@ -340,7 +340,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So if polling { disconnectPolling(reason: reason) } else { - sendWebSocketMessage("", withType: .close, withData: []) + sendWebSocketMessage("", withType: .close, withData: [], completion: {}) closeOutEngine(reason: reason) } } @@ -348,7 +348,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So // We need to take special care when we're polling that we send it ASAP // Also make sure we're on the emitQueue since we're touching postWait private func disconnectPolling(reason: String) { - postWait.append(String(SocketEnginePacketType.close.rawValue)) + postWait.append((String(SocketEnginePacketType.close.rawValue), {})) doRequest(for: createRequestForPostWithPostWait()) {_, _, _ in } closeOutEngine(reason: reason) @@ -366,7 +366,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So DefaultSocketLogger.Logger.log("Switching to WebSockets", type: SocketEngine.logType) - sendWebSocketMessage("", withType: .upgrade, withData: []) + sendWebSocketMessage("", withType: .upgrade, withData: [], completion: {}) polling = false fastUpgrade = false probing = false @@ -384,7 +384,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So DefaultSocketLogger.Logger.log("Flushing probe wait", type: SocketEngine.logType) for waiter in probeWait { - write(waiter.msg, withType: waiter.type, withData: waiter.data) + write(waiter.msg, withType: waiter.type, withData: waiter.data, completion:waiter.completion) } probeWait.removeAll(keepingCapacity: false) @@ -398,7 +398,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So guard let ws = self.ws else { return } for msg in postWait { - ws.write(string: msg) + ws.write(string: msg.msg, completion: msg.completion) } postWait.removeAll(keepingCapacity: false) @@ -544,7 +544,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So } pongsMissed += 1 - write("", withType: .ping, withData: []) + write("", withType: .ping, withData: [], completion: {}) engineQueue.asyncAfter(deadline: DispatchTime.now() + .milliseconds(pingInterval)) {[weak self, id = self.sid] in // Make sure not to ping old connections @@ -600,7 +600,7 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: SocketEngine.logType) fastUpgrade = true - sendPollMessage("", withType: .noop, withData: []) + sendPollMessage("", withType: .noop, withData: [], completion: {}) // After this point, we should not send anymore polling messages } } @@ -610,11 +610,15 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So /// - parameter msg: The message to send. /// - parameter type: The type of this message. /// - parameter data: Any data that this message has. - open func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data]) { + /// - parameter completion: Callback called on transport write completion. + open func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data], completion: @escaping () -> ()) { engineQueue.async { - guard self.connected else { return } + guard self.connected else { + completion() + return + } guard !self.probing else { - self.probeWait.append((msg, type, data)) + self.probeWait.append((msg, type, data, completion)) return } @@ -622,11 +626,11 @@ open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, So if self.polling { DefaultSocketLogger.Logger.log("Writing poll: \(msg) has data: \(data.count != 0)", type: SocketEngine.logType) - self.sendPollMessage(msg, withType: type, withData: data) + self.sendPollMessage(msg, withType: type, withData: data, completion: completion) } else { DefaultSocketLogger.Logger.log("Writing ws: \(msg) has data: \(data.count != 0)", type: SocketEngine.logType) - self.sendWebSocketMessage(msg, withType: type, withData: data) + self.sendWebSocketMessage(msg, withType: type, withData: data, completion: completion) } } } diff --git a/Source/SocketIO/Engine/SocketEnginePollable.swift b/Source/SocketIO/Engine/SocketEnginePollable.swift index faec93ab..29a40bf8 100644 --- a/Source/SocketIO/Engine/SocketEnginePollable.swift +++ b/Source/SocketIO/Engine/SocketEnginePollable.swift @@ -34,7 +34,7 @@ public protocol SocketEnginePollable : SocketEngineSpec { /// A queue of engine.io messages waiting for POSTing /// /// **You should not touch this directly** - var postWait: [String] { get set } + var postWait: [Post] { get set } /// The URLSession that will be used for polling. var session: URLSession? { get } @@ -65,7 +65,7 @@ public protocol SocketEnginePollable : SocketEngineSpec { /// - parameter message: The message to send. /// - parameter withType: The type of message to send. /// - parameter withData: The data associated with this message. - func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data]) + func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data], completion: @escaping () -> ()) /// Call to stop polling and invalidate the URLSession. func stopPolling() @@ -74,12 +74,15 @@ public protocol SocketEnginePollable : SocketEngineSpec { // Default polling methods extension SocketEnginePollable { func createRequestForPostWithPostWait() -> URLRequest { - defer { postWait.removeAll(keepingCapacity: true) } + defer { + for packet in postWait { packet.completion() } + postWait.removeAll(keepingCapacity: true) + } var postStr = "" for packet in postWait { - postStr += "\(packet.utf16.count):\(packet)" + postStr += "\(packet.msg.utf16.count):\(packet.msg)" } DefaultSocketLogger.Logger.log("Created POST string: \(postStr)", type: "SocketEnginePolling") @@ -209,14 +212,17 @@ extension SocketEnginePollable { /// - parameter message: The message to send. /// - parameter withType: The type of message to send. /// - parameter withData: The data associated with this message. - public func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data]) { + /// - parameter completion: Callback called on transport write completion. + public func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data], completion: @escaping () -> ()) { DefaultSocketLogger.Logger.log("Sending poll: \(message) as type: \(type.rawValue)", type: "SocketEnginePolling") - postWait.append(String(type.rawValue) + message) + postWait.append((String(type.rawValue) + message, completion)) for data in datas { if case let .right(bin) = createBinaryDataForSend(using: data) { - postWait.append(bin) + // completion handler will be called on initial message write + // TODO: call completion after last message in batch + postWait.append((bin, {})) } } diff --git a/Source/SocketIO/Engine/SocketEngineSpec.swift b/Source/SocketIO/Engine/SocketEngineSpec.swift index 40785354..c7b073c0 100644 --- a/Source/SocketIO/Engine/SocketEngineSpec.swift +++ b/Source/SocketIO/Engine/SocketEngineSpec.swift @@ -137,7 +137,8 @@ import Starscream /// - parameter msg: The message to send. /// - parameter type: The type of this message. /// - parameter data: Any data that this message has. - func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data]) + /// - parameter completion: Callback called on transport write completion. + func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data], completion: @escaping () -> ()) } extension SocketEngineSpec { @@ -162,7 +163,7 @@ extension SocketEngineSpec { if !cookiesToAdd.isEmpty { req.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: cookiesToAdd) } - + if let extraHeaders = extraHeaders { for (headerName, value) in extraHeaders { req.setValue(value, forHTTPHeaderField: headerName) @@ -179,7 +180,7 @@ extension SocketEngineSpec { } /// Send an engine message (4) - func send(_ msg: String, withData datas: [Data]) { - write(msg, withType: .message, withData: datas) + func send(_ msg: String, withData datas: [Data], completion: (() -> ())? = nil) { + write(msg, withType: .message, withData: datas, completion: completion ?? {}) } } diff --git a/Source/SocketIO/Engine/SocketEngineWebsocket.swift b/Source/SocketIO/Engine/SocketEngineWebsocket.swift index 6dc11ac3..b3fad5ec 100644 --- a/Source/SocketIO/Engine/SocketEngineWebsocket.swift +++ b/Source/SocketIO/Engine/SocketEngineWebsocket.swift @@ -37,14 +37,15 @@ public protocol SocketEngineWebsocket : SocketEngineSpec { /// - parameter message: The message to send. /// - parameter withType: The type of message to send. /// - parameter withData: The data associated with this message. - func sendWebSocketMessage(_ str: String, withType type: SocketEnginePacketType, withData datas: [Data]) + /// - parameter completion: Callback called on transport write completion. + func sendWebSocketMessage(_ str: String, withType type: SocketEnginePacketType, withData datas: [Data], completion: @escaping () -> ()) } // WebSocket methods extension SocketEngineWebsocket { func probeWebSocket() { if ws?.isConnected ?? false { - sendWebSocketMessage("probe", withType: .ping, withData: []) + sendWebSocketMessage("probe", withType: .ping, withData: [], completion: {}) } } @@ -55,14 +56,15 @@ extension SocketEngineWebsocket { /// - parameter message: The message to send. /// - parameter withType: The type of message to send. /// - parameter withData: The data associated with this message. - public func sendWebSocketMessage(_ str: String, withType type: SocketEnginePacketType, withData datas: [Data]) { + /// - parameter completion: Callback called on transport write completion. + public func sendWebSocketMessage(_ str: String, withType type: SocketEnginePacketType, withData datas: [Data], completion: @escaping () -> ()) { DefaultSocketLogger.Logger.log("Sending ws: \(str) as type: \(type.rawValue)", type: "SocketEngineWebSocket") ws?.write(string: "\(type.rawValue)\(str)") for data in datas { if case let .left(bin) = createBinaryDataForSend(using: data) { - ws?.write(data: bin) + ws?.write(data: bin, completion: completion) } } } diff --git a/Source/SocketIO/Manager/SocketManager.swift b/Source/SocketIO/Manager/SocketManager.swift index 126aec1b..ed6ae144 100644 --- a/Source/SocketIO/Manager/SocketManager.swift +++ b/Source/SocketIO/Manager/SocketManager.swift @@ -290,7 +290,7 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa /// - parameter items: The data to send with this event. open func emitAll(_ event: String, withItems items: [Any]) { forAll {socket in - socket.emit(event, with: items) + socket.emit(event, with: items, completion: {}) } } diff --git a/Source/SocketIO/Util/SocketTypes.swift b/Source/SocketIO/Util/SocketTypes.swift index bbc1b6d5..f8cdc050 100644 --- a/Source/SocketIO/Util/SocketTypes.swift +++ b/Source/SocketIO/Util/SocketTypes.swift @@ -73,8 +73,11 @@ public typealias AckCallback = ([Any]) -> () /// A typealias for a normal callback. public typealias NormalCallback = ([Any], SocketAckEmitter) -> () +/// A typealias for a queued POST +public typealias Post = (msg: String, completion: (() -> ())) + typealias JSON = [String: Any] -typealias Probe = (msg: String, type: SocketEnginePacketType, data: [Data]) +typealias Probe = (msg: String, type: SocketEnginePacketType, data: [Data], completion: (() -> ())) typealias ProbeWaitQueue = [Probe] enum Either { diff --git a/Tests/TestSocketIO/SocketMangerTest.swift b/Tests/TestSocketIO/SocketMangerTest.swift index 22da481f..dc764414 100644 --- a/Tests/TestSocketIO/SocketMangerTest.swift +++ b/Tests/TestSocketIO/SocketMangerTest.swift @@ -188,7 +188,7 @@ public class TestSocket : SocketIOClient { super.didDisconnect(reason: reason) } - public override func emit(_ event: String, with items: [Any]) { + public override func emit(_ event: String, with items: [Any], completion: @escaping () -> ()) { expectations[ManagerExpectation.emitAllEventCalled]?.fulfill() expectations[ManagerExpectation.emitAllEventCalled] = nil diff --git a/Tests/TestSocketIO/SocketSideEffectTest.swift b/Tests/TestSocketIO/SocketSideEffectTest.swift index 5c8a77de..49542cee 100644 --- a/Tests/TestSocketIO/SocketSideEffectTest.swift +++ b/Tests/TestSocketIO/SocketSideEffectTest.swift @@ -506,5 +506,5 @@ class TestEngine : SocketEngineSpec { func flushWaitingForPostToWebSocket() { } func parseEngineData(_ data: Data) { } func parseEngineMessage(_ message: String) { } - func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data]) { } + func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data], completion: @escaping () -> ()) { } } diff --git a/Tests/TestSocketIOObjc/SocketObjectiveCTest.m b/Tests/TestSocketIOObjc/SocketObjectiveCTest.m index 1ad34751..28c21b94 100644 --- a/Tests/TestSocketIOObjc/SocketObjectiveCTest.m +++ b/Tests/TestSocketIOObjc/SocketObjectiveCTest.m @@ -67,6 +67,20 @@ - (void)testEmitSyntax { [self.socket emit:@"testEmit" with:@[@YES]]; } +- (void)testEmitWriteCompletionSyntax { + [self.socket emit:@"testEmit" with:@[@YES] completion:^{}]; +} + +- (void)testEmitWriteCompletion { + XCTestExpectation* expect = [self expectationWithDescription:@"Write completion should be called"]; + + [self.socket emit:@"testEmit" with:@[@YES] completion:^{ + [expect fulfill]; + }]; + + [self waitForExpectationsWithTimeout:0.3 handler:nil]; +} + - (void)testRawEmitSyntax { [[self.socket rawEmitView] emit:@"myEvent" with:@[@1]]; } From 28fad62ccd37bcb45a6af0b6a620c9cb746f01f0 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 2 Oct 2018 13:47:03 +0700 Subject: [PATCH 2/5] wrap completion handler to run on handleQueue --- Source/SocketIO/Client/SocketIOClient.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index ac7dbff5..4e70417e 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -295,8 +295,14 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { } func emit(_ data: [Any], ack: Int? = nil, binary: Bool = true, isAck: Bool = false, completion: (() -> ())? = nil) { + // wrap the completion handler so it always runs async via handlerQueue + let wrappedCompletion = {[weak self, completion] in + guard let this = self else { return } + this.manager?.handleQueue.async { completion?() } + } + guard status == .connected else { - completion?(); + wrappedCompletion(); handleClientEvent(.error, data: ["Tried emitting when not connected"]) return } @@ -306,7 +312,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { DefaultSocketLogger.Logger.log("Emitting: \(str), Ack: \(isAck)", type: logType) - manager?.engine?.send(str, withData: packet.binary, completion: completion) + manager?.engine?.send(str, withData: packet.binary, completion: completion != nil ? wrappedCompletion : nil) } /// Call when you wish to tell the server that you've received the event for `ack`. From d763fad4496df113476efc4361795c3e16722699 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 2 Oct 2018 19:05:22 +0700 Subject: [PATCH 3/5] no need to capture completion hander in wrapper --- Source/SocketIO/Client/SocketIOClient.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index 4e70417e..a4c892c8 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -296,7 +296,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { func emit(_ data: [Any], ack: Int? = nil, binary: Bool = true, isAck: Bool = false, completion: (() -> ())? = nil) { // wrap the completion handler so it always runs async via handlerQueue - let wrappedCompletion = {[weak self, completion] in + let wrappedCompletion = {[weak self] in guard let this = self else { return } this.manager?.handleQueue.async { completion?() } } From b3e305fd1448165fa52e0a2d2b2afffbecbbadae Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 2 Oct 2018 20:55:38 +0700 Subject: [PATCH 4/5] Add a variadic method for emit completion handlers in swift --- Source/SocketIO/Client/SocketIOClient.swift | 12 ++++++++++++ Source/SocketIO/Client/SocketIOClientSpec.swift | 10 ++++++++++ Tests/TestSocketIO/SocketSideEffectTest.swift | 5 +++++ 3 files changed, 27 insertions(+) diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index a4c892c8..a0d89a7d 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -221,6 +221,18 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { handleClientEvent(.error, data: [event, items, error]) } } + + /// Send an event to the server, with optional data items and write completion handler. + /// + /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` + /// will be emitted. The structure of the error data is `[eventName, items, theError]` + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. May be left out. + /// - parameter completion: Callback called on transport write completion. + open func emit(_ event: String, _ items: SocketData..., completion: @escaping () -> ()) { + emit([event] + items, completion: completion) + } /// Same as emit, but meant for Objective-C /// diff --git a/Source/SocketIO/Client/SocketIOClientSpec.swift b/Source/SocketIO/Client/SocketIOClientSpec.swift index 38354123..629ee781 100644 --- a/Source/SocketIO/Client/SocketIOClientSpec.swift +++ b/Source/SocketIO/Client/SocketIOClientSpec.swift @@ -101,6 +101,16 @@ public protocol SocketIOClientSpec : AnyObject { /// - parameter items: The items to send with this event. May be left out. func emit(_ event: String, _ items: SocketData...) + /// Send an event to the server, with optional data items and write completion handler. + /// + /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` + /// will be emitted. The structure of the error data is `[eventName, items, theError]` + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. May be left out. + /// - parameter completion: Callback called on transport write completion. + func emit(_ event: String, _ items: SocketData..., completion: @escaping () -> ()) + /// Call when you wish to tell the server that you've received the event for `ack`. /// /// - parameter ack: The ack number. diff --git a/Tests/TestSocketIO/SocketSideEffectTest.swift b/Tests/TestSocketIO/SocketSideEffectTest.swift index 49542cee..72c43f99 100644 --- a/Tests/TestSocketIO/SocketSideEffectTest.swift +++ b/Tests/TestSocketIO/SocketSideEffectTest.swift @@ -27,6 +27,11 @@ class SocketSideEffectTest: XCTestCase { XCTAssertEqual(socket.currentAck, 1) } + func testEmitCompletionSyntax() { + socket.emit("test", completion: {}) + socket.emit("test", "thing", completion: {}) + } + func testHandleAck() { let expect = expectation(description: "handled ack") socket.emitWithAck("test").timingOut(after: 0) {data in From 09fc43349ff5c2736cb24cc015dfdd564d2302c3 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 2 Oct 2018 21:08:55 +0700 Subject: [PATCH 5/5] convert SocketData to serialisable socket representation --- Source/SocketIO/Client/SocketIOClient.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index a0d89a7d..7ac8b742 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -231,7 +231,14 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { /// - parameter items: The items to send with this event. May be left out. /// - parameter completion: Callback called on transport write completion. open func emit(_ event: String, _ items: SocketData..., completion: @escaping () -> ()) { - emit([event] + items, completion: completion) + do { + try emit(event, with: items.map({ try $0.socketRepresentation() }), completion: completion) + } catch { + DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", + type: logType) + + handleClientEvent(.error, data: [event, items, error]) + } } /// Same as emit, but meant for Objective-C