diff --git a/Examples/HubSamplePhone/Info.plist b/Examples/HubSamplePhone/Info.plist
index f41381c..f87da23 100644
--- a/Examples/HubSamplePhone/Info.plist
+++ b/Examples/HubSamplePhone/Info.plist
@@ -20,6 +20,11 @@
1
LSRequiresIPhoneOS
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
@@ -41,10 +46,5 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
- NSAppTransportSecurity
-
- NSAllowsArbitraryLoads
-
-
diff --git a/Examples/HubSamplePhone/ViewController.swift b/Examples/HubSamplePhone/ViewController.swift
index ee8326f..b35d077 100644
--- a/Examples/HubSamplePhone/ViewController.swift
+++ b/Examples/HubSamplePhone/ViewController.swift
@@ -11,7 +11,7 @@ import SignalRClient
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// Update the Url accordingly
- private let serverUrl = "http://192.168.86.250:5000/chat" // /chat or /chatLongPolling or /chatWebSockets
+ private let serverUrl = "http://127.0.0.1:5000/chat" // /chat or /chatLongPolling or /chatWebSockets
private let dispatchQueue = DispatchQueue(label: "hubsamplephone.queue.dispatcheueuq")
private var chatHubConnection: HubConnection?
@@ -29,20 +29,19 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
self.chatTableView.delegate = self
self.chatTableView.dataSource = self
}
-
+
override func viewDidAppear(_ animated: Bool) {
let alert = UIAlertController(title: "Enter your Name", message:"", preferredStyle: UIAlertController.Style.alert)
alert.addTextField() { textField in textField.placeholder = "Name"}
let OKAction = UIAlertAction(title: "OK", style: .default) { action in
self.name = alert.textFields?.first?.text ?? "John Doe"
-
self.chatHubConnectionDelegate = ChatHubConnectionDelegate(controller: self)
self.chatHubConnection = HubConnectionBuilder(url: URL(string: self.serverUrl)!)
.withLogging(minLogLevel: .debug)
.withAutoReconnect()
.withHubConnectionDelegate(delegate: self.chatHubConnectionDelegate!)
.build()
-
+
self.chatHubConnection!.on(method: "NewMessage", callback: {(user: String, message: String) in
self.appendMessage(message: "\(user): \(message)")
})
@@ -51,11 +50,11 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
alert.addAction(OKAction)
self.present(alert, animated: true)
}
-
+
override func viewWillDisappear(_ animated: Bool) {
chatHubConnection?.stop()
}
-
+
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
diff --git a/Examples/SignalRClient.xcodeproj/project.pbxproj b/Examples/SignalRClient.xcodeproj/project.pbxproj
index b603309..8ff25f5 100644
--- a/Examples/SignalRClient.xcodeproj/project.pbxproj
+++ b/Examples/SignalRClient.xcodeproj/project.pbxproj
@@ -74,8 +74,6 @@
7391A94722510170007BEF23 /* TransferFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7391A91922510170007BEF23 /* TransferFormat.swift */; };
7391A94822510170007BEF23 /* HubProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7391A91A22510170007BEF23 /* HubProtocol.swift */; };
7391A94922510170007BEF23 /* HubProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7391A91A22510170007BEF23 /* HubProtocol.swift */; };
- 7391A94A22510170007BEF23 /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7391A91B22510170007BEF23 /* Util.swift */; };
- 7391A94B22510170007BEF23 /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7391A91B22510170007BEF23 /* Util.swift */; };
7391A94E22510170007BEF23 /* JSONHubProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7391A91D22510170007BEF23 /* JSONHubProtocol.swift */; };
7391A94F22510170007BEF23 /* JSONHubProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7391A91D22510170007BEF23 /* JSONHubProtocol.swift */; };
7391A95022510170007BEF23 /* HttpConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7391A91E22510170007BEF23 /* HttpConnection.swift */; };
@@ -207,7 +205,6 @@
7391A91822510170007BEF23 /* NegotiationResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NegotiationResponse.swift; sourceTree = ""; };
7391A91922510170007BEF23 /* TransferFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransferFormat.swift; sourceTree = ""; };
7391A91A22510170007BEF23 /* HubProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HubProtocol.swift; sourceTree = ""; };
- 7391A91B22510170007BEF23 /* Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = ""; };
7391A91D22510170007BEF23 /* JSONHubProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONHubProtocol.swift; sourceTree = ""; };
7391A91E22510170007BEF23 /* HttpConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpConnection.swift; sourceTree = ""; };
7391A91F22510170007BEF23 /* ConnectionDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionDelegate.swift; sourceTree = ""; };
@@ -380,7 +377,6 @@
7391A91822510170007BEF23 /* NegotiationResponse.swift */,
7391A91922510170007BEF23 /* TransferFormat.swift */,
7391A91A22510170007BEF23 /* HubProtocol.swift */,
- 7391A91B22510170007BEF23 /* Util.swift */,
7391A91D22510170007BEF23 /* JSONHubProtocol.swift */,
7391A91E22510170007BEF23 /* HttpConnection.swift */,
7391A91F22510170007BEF23 /* ConnectionDelegate.swift */,
@@ -629,7 +625,6 @@
7391A92F22510170007BEF23 /* ServerInvocationHandler.swift in Sources */,
7391A94322510170007BEF23 /* HttpClientProtocol.swift in Sources */,
7391A93122510170007BEF23 /* DefaultHttpClient.swift in Sources */,
- 7391A94B22510170007BEF23 /* Util.swift in Sources */,
7391A93F22510170007BEF23 /* HandshakeProtocol.swift in Sources */,
5ABD6A632439AE6B00BFA93D /* ReconnectableConnection.swift in Sources */,
7391A94722510170007BEF23 /* TransferFormat.swift in Sources */,
@@ -667,7 +662,6 @@
7391A92E22510170007BEF23 /* ServerInvocationHandler.swift in Sources */,
7391A94222510170007BEF23 /* HttpClientProtocol.swift in Sources */,
7391A93022510170007BEF23 /* DefaultHttpClient.swift in Sources */,
- 7391A94A22510170007BEF23 /* Util.swift in Sources */,
7391A93E22510170007BEF23 /* HandshakeProtocol.swift in Sources */,
5ABD6A622439AE6B00BFA93D /* ReconnectableConnection.swift in Sources */,
7391A94622510170007BEF23 /* TransferFormat.swift in Sources */,
diff --git a/Sources/SignalRClient/HubConnection.swift b/Sources/SignalRClient/HubConnection.swift
index 785e37d..bafb740 100755
--- a/Sources/SignalRClient/HubConnection.swift
+++ b/Sources/SignalRClient/HubConnection.swift
@@ -90,7 +90,8 @@ public class HubConnection {
// TODO: add negative test (e.g. invalid protocol)
let handshakeRequest = HandshakeProtocol.createHandshakeRequest(hubProtocol: hubProtocol)
logger.log(logLevel: .debug, message: "Sending handshake request: \(handshakeRequest)")
- connection.send(data: "\(handshakeRequest)".data(using: .utf8)!) { error in
+ connection.send(data: "\(handshakeRequest)".data(using: .utf8)!) { [weak self] error in
+ guard let self else { return }
if let e = error {
self.logger.log(logLevel: .error, message: "Sending handshake request failed: \(e)")
// TODO: (BUG) if this fails when reconnecting the callback should not be called and there
@@ -156,7 +157,8 @@ public class HubConnection {
let invocationData = try hubProtocol.writeMessage(message: invocationMessage)
resetKeepAlive()
- connection.send(data: invocationData, sendDidComplete: { error in
+ connection.send(data: invocationData, sendDidComplete: { [weak self] error in
+ guard let self else { return }
if error == nil {
self.resetKeepAlive()
}
@@ -281,7 +283,8 @@ public class HubConnection {
let cancelInvocationMessage = CancelInvocationMessage(invocationId: streamHandle.invocationId)
do {
let cancelInvocationData = try hubProtocol.writeMessage(message: cancelInvocationMessage)
- connection.send(data: cancelInvocationData, sendDidComplete: {error in
+ connection.send(data: cancelInvocationData, sendDidComplete: { [weak self] error in
+ guard let self else { return }
if let e = error {
self.logger.log(logLevel: .error, message: "Sending cancellation of server side streaming hub returned error: \(e)")
self.callbackQueue.async {
@@ -312,7 +315,8 @@ public class HubConnection {
let invocationMessage = invocationHandler.createInvocationMessage(invocationId: id, method: method, arguments: arguments, streamIds: [])
let invocationData = try hubProtocol.writeMessage(message: invocationMessage)
- connection.send(data: invocationData) { error in
+ connection.send(data: invocationData) { [weak self] error in
+ guard let self else { return }
if let e = error {
self.logger.log(logLevel: .error, message: "Invoking server hub method \(method) returned error: \(e)")
self.failInvocationWithError(invocationHandler: invocationHandler, invocationId: id, error: e)
@@ -364,17 +368,20 @@ public class HubConnection {
// TODO: (BUG) if this fails when reconnecting the callback should not be called and there
// will be no further reconnect attempts
logger.log(logLevel: .error, message: "Parsing handshake response failed: \(e)")
- callbackQueue.async {
+ callbackQueue.async { [weak self] in
+ guard let self else { return }
self.delegate?.connectionDidFailToOpen(error: e)
}
return
}
if originalHandshakeStatus.isReconnect {
- callbackQueue.async {
+ callbackQueue.async { [weak self] in
+ guard let self else { return }
self.delegate?.connectionDidReconnect()
}
} else {
- callbackQueue.async {
+ callbackQueue.async { [weak self] in
+ guard let self else { return }
self.delegate?.connectionDidOpen(hubConnection: self)
}
resetKeepAlive()
@@ -515,7 +522,10 @@ public class HubConnection {
}
logger.log(logLevel: .debug, message: "Resetting keep alive")
keepAlivePingTask!.cancel()
- keepAlivePingTask = DispatchWorkItem { self.sendKeepAlivePing() }
+ keepAlivePingTask = DispatchWorkItem { [weak self] in
+ guard let self else { return }
+ self.sendKeepAlivePing()
+ }
hubConnectionQueue.asyncAfter(deadline: DispatchTime.now() + keepAliveInterval, execute: keepAlivePingTask!)
}
}
@@ -531,7 +541,8 @@ public class HubConnection {
do {
let cachedPingMessage = try hubProtocol.writeMessage(message: PingMessage.instance)
logger.log(logLevel: .debug, message: "Sending keep alive")
- connection.send(data: cachedPingMessage, sendDidComplete: { error in
+ connection.send(data: cachedPingMessage, sendDidComplete: { [weak self] error in
+ guard let self else { return }
if let error = error {
self.logger.log(logLevel: .error, message: "Keep alive send error: \(error.localizedDescription)")
} else {
diff --git a/Sources/SignalRClient/HubConnectionBuilder.swift b/Sources/SignalRClient/HubConnectionBuilder.swift
index e0aba64..cd9de27 100644
--- a/Sources/SignalRClient/HubConnectionBuilder.swift
+++ b/Sources/SignalRClient/HubConnectionBuilder.swift
@@ -24,7 +24,7 @@ public class HubConnectionBuilder {
private let httpConnectionOptions = HttpConnectionOptions()
private let hubConnectionOptions = HubConnectionOptions()
private var logger: Logger = NullLogger()
- private var delegate: HubConnectionDelegate?
+ private weak var delegate: HubConnectionDelegate?
private var reconnectPolicy: ReconnectPolicy = NoReconnectPolicy()
private var permittedTransportTypes: TransportType = .all
private var transportFactory: ((Logger, TransportType) -> TransportFactory) =
diff --git a/Sources/SignalRClient/LongPollingTransport.swift b/Sources/SignalRClient/LongPollingTransport.swift
index 6016dd1..892b178 100644
--- a/Sources/SignalRClient/LongPollingTransport.swift
+++ b/Sources/SignalRClient/LongPollingTransport.swift
@@ -9,7 +9,7 @@ import Foundation
public class LongPollingTransport: Transport {
- public var delegate: TransportDelegate?
+ public weak var delegate: TransportDelegate?
private let logger: Logger
private let closeQueue = DispatchQueue(label: "LongPollingTransportCloseQueue")
@@ -44,6 +44,7 @@ public class LongPollingTransport: Transport {
return
}
httpClient.post(url: url, body: data) { (responseOptional, errorOptional) in
+ //If for any reason you need self instance please added as weak to prevent ARC count up and lead to memory leak
if let error = errorOptional {
sendDidComplete(error)
} else if let response = responseOptional {
@@ -57,12 +58,14 @@ public class LongPollingTransport: Transport {
}
public func close() {
- closeQueue.sync {
+ closeQueue.sync { [weak self] in
+ guard let self else { return }
if !closeCalled {
closeCalled = true
active = false
self.logger.log(logLevel: .debug, message: "Sending LongPolling session DELETE request...")
- self.httpClient?.delete(url: self.url!, completionHandler: { (_, errorOptional) in
+ self.httpClient?.delete(url: self.url!, completionHandler: { [weak self] (_, errorOptional) in
+ guard let self else { return }
if let error = errorOptional {
self.logger.log(logLevel: .error, message: "Error while DELETE-ing long polling session: \(error)")
self.delegate?.transportDidClose(error)
@@ -81,7 +84,10 @@ public class LongPollingTransport: Transport {
if self.active {
let pollUrl = self.getPollUrl()
self.logger.log(logLevel: .debug, message: "Polling \(pollUrl)")
- self.httpClient?.get(url: pollUrl, completionHandler: self.handlePollResponse(response:error:))
+ self.httpClient?.get(url: pollUrl, completionHandler: { [weak self] response,error in
+ guard let self else { return }
+ self.handlePollResponse(response: response, error: error)
+ })
} else {
self.logger.log(logLevel: .debug, message: "Long Polling transport polling complete.")
self.close()
diff --git a/Sources/SignalRClient/WebsocketsTransport.swift b/Sources/SignalRClient/WebsocketsTransport.swift
index 74416be..3df7acc 100644
--- a/Sources/SignalRClient/WebsocketsTransport.swift
+++ b/Sources/SignalRClient/WebsocketsTransport.swift
@@ -18,7 +18,7 @@ public class WebsocketsTransport: NSObject, Transport, URLSessionWebSocketDelega
private var isTransportClosed = false
- public var delegate: TransportDelegate?
+ public weak var delegate: TransportDelegate?
public let inherentKeepAlive = false
init(logger: Logger) {
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..e97eb96
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6 @@
+{
+ "name": "SignalR-Client-Swift",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {}
+}