diff --git a/README.md b/README.md index c5d6b91..73f2882 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,9 @@ SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url options:@ - Can be used from Objective-C ##Installation -Requires Swift 2/Xcode 7 +Requires Swift 2.2/Xcode 7.3 + +If you need Swift 2.1/Xcode 7.2 use v5.5.0 (Pre-Swift 2.2 support is no longer maintained) If you need Swift 1.2/Xcode 6.3/4 use v2.4.5 (Pre-Swift 2 support is no longer maintained) @@ -86,7 +88,7 @@ Carthage ----------------- Add this line to your `Cartfile`: ``` -github "socketio/socket.io-client-swift" ~> 5.5.0 # Or latest version +github "socketio/socket.io-client-swift" ~> 6.0.0 # Or latest version ``` Run `carthage update --platform ios,macosx`. @@ -100,7 +102,7 @@ source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' use_frameworks! -pod 'Socket.IO-Client-Swift', '~> 5.5.0' # Or latest version +pod 'Socket.IO-Client-Swift', '~> 6.0.0' # Or latest version ``` Install pods: @@ -128,7 +130,7 @@ CocoaSeeds Add this line to your `Seedfile`: ``` -github "socketio/socket.io-client-swift", "v5.5.0", :files => "Source/*.swift" # Or latest version +github "socketio/socket.io-client-swift", "v6.0.0", :files => "Source/*.swift" # Or latest version ``` Run `seed install`. diff --git a/Socket.IO-Client-Swift.podspec b/Socket.IO-Client-Swift.podspec index 0b5e3ca..42a8ef9 100644 --- a/Socket.IO-Client-Swift.podspec +++ b/Socket.IO-Client-Swift.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Socket.IO-Client-Swift" s.module_name = "SocketIOClientSwift" - s.version = "5.5.0" + s.version = "6.0.0" s.summary = "Socket.IO-client for iOS and OS X" s.description = <<-DESC Socket.IO-client for iOS and OS X. @@ -14,7 +14,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.10' s.tvos.deployment_target = '9.0' - s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v5.5.0' } + s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v6.0.0' } s.source_files = "Source/**/*.swift" s.requires_arc = true # s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files diff --git a/SocketIO-MacTests/SocketParserTest.swift b/SocketIO-MacTests/SocketParserTest.swift index d17bb44..9513fcd 100644 --- a/SocketIO-MacTests/SocketParserTest.swift +++ b/SocketIO-MacTests/SocketParserTest.swift @@ -113,7 +113,7 @@ class SocketParserTest: XCTestCase { func validateParseResult(message: String) { let validValues = SocketParserTest.packetTypes[message]! let packet = testSocket.parseString(message) - let type = message.substringWithRange(Range(start: message.startIndex, end: message.startIndex.advancedBy(1))) + let type = message.substringWithRange(Range(message.startIndex.. Void) { - if !polling || closed || invalidated { - DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEnginePolling") - return - } - - DefaultSocketLogger.Logger.log("Doing polling request", type: "SocketEnginePolling") - - session?.dataTaskWithRequest(req, completionHandler: callback).resume() + if !polling || closed || invalidated || fastUpgrade { + DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEnginePolling") + return + } + + DefaultSocketLogger.Logger.log("Doing polling request", type: "SocketEnginePolling") + + session?.dataTaskWithRequest(req, completionHandler: callback).resume() } func doLongPoll(req: NSURLRequest) { doRequest(req) {[weak self] data, res, err in - guard let this = self else { return } + guard let this = self where this.polling else { return } if err != nil || data == nil { DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling") @@ -123,7 +123,7 @@ extension SocketEnginePollable { return } - + DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling") if let str = String(data: data!, encoding: NSUTF8StringEncoding) { diff --git a/Source/SocketIOClient.swift b/Source/SocketIOClient.swift index d3a0b36..981f744 100644 --- a/Source/SocketIOClient.swift +++ b/Source/SocketIOClient.swift @@ -28,7 +28,17 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable public let socketURL: NSURL public private(set) var engine: SocketEngineSpec? - public private(set) var status = SocketIOClientStatus.NotConnected + public private(set) var status = SocketIOClientStatus.NotConnected { + didSet { + switch status { + case .Connected: + reconnecting = false + currentReconnectAttempt = 0 + default: + break + } + } + } public var forceNew = false public var nsp = "/" @@ -46,8 +56,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable private var anyHandler: ((SocketAnyEvent) -> Void)? private var currentReconnectAttempt = 0 private var handlers = [SocketEventHandler]() - private var reconnectTimer: NSTimer? private var ackHandlers = SocketAckManager() + private var reconnecting = false private(set) var currentAck = -1 private(set) var handleQueue = dispatch_get_main_queue() @@ -55,9 +65,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable var waitingPackets = [SocketPacket]() - /** - Type safe way to create a new SocketIOClient. opts can be omitted - */ + /// Type safe way to create a new SocketIOClient. opts can be omitted public init(socketURL: NSURL, options: Set = []) { self.options = options self.socketURL = socketURL @@ -94,10 +102,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable super.init() } - /** - Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity. - If using Swift it's recommended to use `init(socketURL: NSURL, options: Set)` - */ + /// Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity. + /// If using Swift it's recommended to use `init(socketURL: NSURL, options: Set)` public convenience init(socketURL: NSURL, options: NSDictionary?) { self.init(socketURL: socketURL, options: options?.toSocketOptionsSet() ?? []) } @@ -127,26 +133,17 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable return engine! } - private func clearReconnectTimer() { - reconnectTimer?.invalidate() - reconnectTimer = nil - } - @available(*, deprecated=5.3, message="Please use disconnect()") public func close() { disconnect() } - /** - Connect to the server. - */ + /// Connect to the server. public func connect() { connect(timeoutAfter: 0, withTimeoutHandler: nil) } - /** - Connect to the server. If we aren't connected after timeoutAfter, call handler - */ + /// Connect to the server. If we aren't connected after timeoutAfter, call handler public func connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?) { assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)") @@ -203,8 +200,6 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable func didConnect() { DefaultSocketLogger.Logger.log("Socket connected", type: logType) status = .Connected - currentReconnectAttempt = 0 - clearReconnectTimer() // Don't handle as internal because something crazy could happen where // we disconnect before it's handled @@ -224,10 +219,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable handleEvent("disconnect", data: [reason], isInternalMessage: true) } - /** - Disconnects the socket. Only reconnect the same socket if you know what you're doing. - Will turn off automatic reconnects. - */ + /// Disconnects the socket. Only reconnect the same socket if you know what you're doing. + /// Will turn off automatic reconnects. public func disconnect() { DefaultSocketLogger.Logger.log("Closing socket", type: logType) @@ -235,16 +228,12 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable didDisconnect("Disconnect") } - /** - Send a message to the server - */ + /// Send a message to the server public func emit(event: String, _ items: AnyObject...) { emit(event, withItems: items) } - /** - Same as emit, but meant for Objective-C - */ + /// Same as emit, but meant for Objective-C public func emit(event: String, withItems items: [AnyObject]) { guard status == .Connected else { handleEvent("error", data: ["Tried emitting \(event) when not connected"], isInternalMessage: true) @@ -301,10 +290,15 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable public func engineDidClose(reason: String) { waitingPackets.removeAll() + + if status != .Closed { + status = .NotConnected + } if status == .Closed || !reconnects { didDisconnect(reason) - } else if status != .Reconnecting { + } else if !reconnecting { + reconnecting = true tryReconnectWithReason(reason) } } @@ -325,9 +319,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable ackHandlers.executeAck(ack, items: data) } - /** - Causes an event to be handled. Only use if you know what you're doing. - */ + /// Causes an event to be handled. Only use if you know what you're doing. public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int = -1) { guard status == .Connected || isInternalMessage else { return @@ -344,9 +336,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable } } - /** - Leaves nsp and goes back to / - */ + /// Leaves nsp and goes back to / public func leaveNamespace() { if nsp != "/" { engine?.send("1\(nsp)", withData: []) @@ -354,9 +344,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable } } - /** - Joins namespace - */ + /// Joins namespace public func joinNamespace(namespace: String) { nsp = namespace @@ -366,28 +354,22 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable } } - /** - Removes handler(s) - */ + /// Removes handler(s) based on name public func off(event: String) { DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: logType, args: event) handlers = handlers.filter { $0.event != event } } - /** - Removes a handler with the specified UUID gotten from an `on` or `once` - */ + /// Removes a handler with the specified UUID gotten from an `on` or `once` public func off(id id: NSUUID) { DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id) handlers = handlers.filter { $0.id != id } } - /** - Adds a handler for an event. - Returns: A unique id for the handler - */ + /// Adds a handler for an event. + /// Returns: A unique id for the handler public func on(event: String, callback: NormalCallback) -> NSUUID { DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event) @@ -397,10 +379,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable return handler.id } - /** - Adds a single-use handler for an event. - Returns: A unique id for the handler - */ + /// Adds a single-use handler for an event. + /// Returns: A unique id for the handler public func once(event: String, callback: NormalCallback) -> NSUUID { DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: logType, args: event) @@ -417,9 +397,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable return handler.id } - /** - Adds a handler that will be called on every event. - */ + /// Adds a handler that will be called on every event. public func onAny(handler: (SocketAnyEvent) -> Void) { anyHandler = handler } @@ -443,44 +421,34 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable } } - /** - Tries to reconnect to the server. - */ + /// Tries to reconnect to the server. public func reconnect() { - tryReconnectWithReason("manual reconnect") + guard !reconnecting else { return } + + engine?.disconnect("manual reconnect") } - /** - Removes all handlers. - Can be used after disconnecting to break any potential remaining retain cycles. - */ + /// Removes all handlers. + /// Can be used after disconnecting to break any potential remaining retain cycles. public func removeAllHandlers() { handlers.removeAll(keepCapacity: false) } private func tryReconnectWithReason(reason: String) { - if reconnectTimer == nil { + if reconnecting { DefaultSocketLogger.Logger.log("Starting reconnect", type: logType) handleEvent("reconnect", data: [reason], isInternalMessage: true) - - status = .Reconnecting - - dispatch_async(dispatch_get_main_queue()) { - self.reconnectTimer = NSTimer.scheduledTimerWithTimeInterval(Double(self.reconnectWait), - target: self, selector: "_tryReconnect", userInfo: nil, repeats: true) - } + + _tryReconnect() } } @objc private func _tryReconnect() { - if status == .Connected { - clearReconnectTimer() - + if !reconnecting { return } if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects { - clearReconnectTimer() didDisconnect("Reconnect Failed") return @@ -492,6 +460,10 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable currentReconnectAttempt += 1 connect() + + let dispatchAfter = dispatch_time(DISPATCH_TIME_NOW, Int64(UInt64(reconnectWait) * NSEC_PER_SEC)) + + dispatch_after(dispatchAfter, dispatch_get_main_queue(), _tryReconnect) } } diff --git a/Source/SocketIOClientStatus.swift b/Source/SocketIOClientStatus.swift index e8720c6..13e82b9 100644 --- a/Source/SocketIOClientStatus.swift +++ b/Source/SocketIOClientStatus.swift @@ -25,7 +25,7 @@ import Foundation @objc public enum SocketIOClientStatus: Int, CustomStringConvertible { - case NotConnected, Closed, Connecting, Connected, Reconnecting + case NotConnected, Closed, Connecting, Connected public var description: String { switch self { @@ -37,8 +37,6 @@ import Foundation return "Connecting" case Connected: return "Connected" - case Reconnecting: - return "Reconnecting" } } } \ No newline at end of file