diff --git a/README.md b/README.md index 2250fbc..c2fb36e 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ socket.on("connect") {data, ack in } socket.on("currentAmount") {data, ack in - if let cur = data[0] as? Double { + if let cur = data?[0] as? Double { socket.emitWithAck("canUpdate", cur)(timeoutAfter: 0) {data in socket.emit("update", ["amount": cur + 2.50]) } - ack?["Got your currentAmount", "dude"] + ack?("Got your currentAmount", "dude") } } @@ -26,20 +26,20 @@ socket.connect() ##Objective-C Example ```objective-c -SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8080" options:nil]; +SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8080" opts:nil]; -[socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) { +[socket onObjectiveC:@"connect" callback:^(NSArray* data, void (^ack)(NSArray*)) { NSLog(@"socket connected"); }]; -[socket on:@"currentAmount" callback:^(NSArray* data, SocketAckEmitter* ack) { +[socket onObjectiveC:@"currentAmount" callback:^(NSArray* data, void (^ack)(NSArray*)) { double cur = [[data objectAtIndex:0] floatValue]; [socket emitWithAck:@"canUpdate" withItems:@[@(cur)]](0, ^(NSArray* data) { [socket emit:@"update" withItems:@[@{@"amount": @(cur + 2.50)}]]; }); - ack[@[@"Got your currentAmount, ", @"dude"]]; + ack(@[@"Got your currentAmount, ", @"dude"]); }]; [socket connect]; @@ -64,7 +64,7 @@ Carthage ----------------- Add this line to your `Cartfile`: ``` -github "socketio/socket.io-client-swift" ~> 3.0.1 # Or latest version +github "socketio/socket.io-client-swift" ~> 3.0.2 # Or latest version ``` Run `carthage update --platform ios,macosx`. @@ -83,7 +83,7 @@ source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' use_frameworks! -pod 'Socket.IO-Client-Swift', '~> 3.0.1' # Or latest version +pod 'Socket.IO-Client-Swift', '~> 3.0.2' # Or latest version ``` Install pods: @@ -107,9 +107,7 @@ Objective-C: ##API Constructors ----------- -`init(socketURL: String, opts:NSDictionary? = nil)` - Constructs a new client for the given URL. opts can be omitted (will use default values) - -`convenience init(socketURL: String, options:NSDictionary?)` - Same as above, but meant for Objective-C. See Objective-C Example. +`init(socketURL: String, opts: NSDictionary? = nil)` - Constructs a new client for the given URL. opts can be omitted (will use default values) note: If your socket.io server is secure, you need to specify `https` in your socketURL. Options ------- @@ -130,18 +128,19 @@ Options Methods ------- -1. `on(event: String, callback: ((data: [AnyObject], ack: SocketAckEmitter?) -> Void))` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example. +1. `on(name: String, callback: ((data: [AnyObject], ack: SocketAckEmitter?) -> Void))` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example. 3. `onAny(callback:((event: String, items: AnyObject?)) -> Void)` - Adds a handler for all events. It will be called on any received event. 4. `emit(event: String, _ items: AnyObject...)` - Sends a message. Can send multiple items. 5. `emit(event: String, withItems items: [AnyObject])` - `emit` for Objective-C -6. `emitWithAck(event: String, _ items: AnyObject...) -> (timeoutAfter:UInt64, callback:(NSArray?) -> Void) -> Void` - Sends a message that requests an acknowledgement from the server. Returns a function which you can use to add a handler. See example. Note: The message is not sent until you call the returned function. +6. `emitWithAck(event: String, _ items: AnyObject...) -> (timeoutAfter: UInt64, callback: (NSArray?) -> Void) -> Void` - Sends a message that requests an acknowledgement from the server. Returns a function which you can use to add a handler. See example. Note: The message is not sent until you call the returned function. 7. `emitWithAck(event: String, withItems items: [AnyObject]) -> (UInt64, (NSArray?) -> Void) -> Void` - `emitWithAck` for Objective-C. Note: The message is not sent until you call the returned function. 8. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection. 9. `connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called. -10. `close(fast fast: Bool)` - Closes the socket. Once a socket is closed it should not be reopened. Pass true to fast if you're closing from a background task. +10. `close()` - Closes the socket. Once a socket is closed it should not be reopened. 11. `reconnect()` - Causes the client to reconnect to the server. 12. `joinNamespace()` - Causes the client to join nsp. Shouldn't need to be called unless you change nsp manually. 13. `leaveNamespace()` - Causes the client to leave the nsp and go back to / +14. `once(event: String, callback: NormalCallback)` - Adds a handler that will only be executed once. Client Events ------ diff --git a/Socket.IO-Client-Swift.podspec b/Socket.IO-Client-Swift.podspec index 098b719..600639c 100644 --- a/Socket.IO-Client-Swift.podspec +++ b/Socket.IO-Client-Swift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Socket.IO-Client-Swift" - s.version = "3.0.1" + s.version = "3.0.2" s.summary = "Socket.IO-client for iOS and OS X" s.description = <<-DESC Socket.IO-client for iOS and OS X. @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.author = { "Erik" => "nuclear.ace@gmail.com" } s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.10' - s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v3.0.1' } + s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v3.0.2' } s.source_files = "SocketIOClientSwift/**/*.swift" s.requires_arc = true # s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files diff --git a/SocketIOClientSwift/SocketEngine.swift b/SocketIOClientSwift/SocketEngine.swift index ba3d214..fd9b654 100644 --- a/SocketIOClientSwift/SocketEngine.swift +++ b/SocketIOClientSwift/SocketEngine.swift @@ -99,6 +99,19 @@ public final class SocketEngine: NSObject, WebSocketDelegate { deinit { Logger.log("Engine is being deinit", type: logType) } + + private func checkIfMessageIsBase64Binary(var message: String) { + if message.hasPrefix("b4") { + // binary in base64 string + message.removeRange(Range(start: message.startIndex, + end: message.startIndex.advancedBy(2))) + + if let data = NSData(base64EncodedString: message, + options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) { + client?.parseBinaryData(data) + } + } + } public func close(fast fast: Bool) { Logger.log("Engine is being closed. Fast: %@", type: logType, args: fast) @@ -364,19 +377,6 @@ public final class SocketEngine: NSObject, WebSocketDelegate { } } - private func checkIfMessageIsBase64Binary(var message: String) { - if message.hasPrefix("b4") { - // binary in base64 string - message.removeRange(Range(start: message.startIndex, - end: message.startIndex.advancedBy(2))) - - if let data = NSData(base64EncodedString: message, - options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) { - client?.parseBinaryData(data) - } - } - } - private func handleMessage(message: String) { client?.parseSocketMessage(message) } @@ -492,11 +492,17 @@ public final class SocketEngine: NSObject, WebSocketDelegate { var reader = SocketStringReader(message: str) while reader.hasNext { - let n = reader.readUntilStringOccurence(":") - let str = reader.read(Int(n)!) - - dispatch_async(handleQueue) { - self.parseEngineMessage(str, fromPolling: true) + if let n = Int(reader.readUntilStringOccurence(":")) { + let str = reader.read(n) + + dispatch_async(handleQueue) { + self.parseEngineMessage(str, fromPolling: true) + } + } else { + dispatch_async(handleQueue) { + self.parseEngineMessage(str, fromPolling: true) + } + break } } } diff --git a/SocketIOClientSwift/SocketEventHandler.swift b/SocketIOClientSwift/SocketEventHandler.swift index 7300d5b..e518e4c 100644 --- a/SocketIOClientSwift/SocketEventHandler.swift +++ b/SocketIOClientSwift/SocketEventHandler.swift @@ -31,9 +31,11 @@ private func emitAckCallback(socket: SocketIOClient, num: Int?) -> SocketAckEmit struct SocketEventHandler { let event: String let callback: NormalCallback + let id: NSUUID - init(event: String, callback: NormalCallback) { + init(event: String, id: NSUUID = NSUUID(), callback: NormalCallback) { self.event = event + self.id = id self.callback = callback } diff --git a/SocketIOClientSwift/SocketIOClient.swift b/SocketIOClientSwift/SocketIOClient.swift index 4cc9e09..f72214a 100644 --- a/SocketIOClientSwift/SocketIOClient.swift +++ b/SocketIOClientSwift/SocketIOClient.swift @@ -133,12 +133,11 @@ public final class SocketIOClient: NSObject, SocketEngineClient { Will turn off automatic reconnects. Pass true to fast if you're closing from a background task */ - public func close(fast fast: Bool) { + public func close() { Logger.log("Closing socket", type: logType) reconnects = false - status = SocketIOClientStatus.Closed - engine?.close(fast: fast) + didDisconnect("Closed") } /** @@ -151,8 +150,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient { /** Connect to the server. If we aren't connected after timeoutAfter, call handler */ - public func connect(timeoutAfter timeoutAfter:Int, - withTimeoutHandler handler:(() -> Void)?) { + public func connect(timeoutAfter timeoutAfter: Int, + withTimeoutHandler handler: (() -> Void)?) { assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)") guard status != .Connected else { @@ -222,7 +221,6 @@ public final class SocketIOClient: NSObject, SocketEngineClient { Logger.log("Disconnected: %@", type: logType, args: reason) status = .Closed - reconnects = false // Make sure the engine is actually dead. @@ -241,8 +239,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient { /** Same as close */ - public func disconnect(fast fast: Bool) { - close(fast: fast) + public func disconnect() { + close() } /** @@ -414,6 +412,23 @@ public final class SocketIOClient: NSObject, SocketEngineClient { handlers.append(handler) } + /** + Adds a single-use handler for an event. + */ + public func once(event: String, callback: NormalCallback) { + Logger.log("Adding once handler for event: %@", type: logType, args: event) + + let id = NSUUID() + + let handler = SocketEventHandler(event: event, id: id) {[weak self] (data, ack: SocketAckEmitter?) in + guard let this = self else {return} + this.handlers = ContiguousArray(this.handlers.filter {$0.id != id}) + callback(data, ack) + } + + handlers.append(handler) + } + /** Removes all handlers. Can be used after disconnecting to break any potential remaining retain cycles. diff --git a/SocketIOClientSwift/SocketTypes.swift b/SocketIOClientSwift/SocketTypes.swift index 3c07353..09fb67a 100644 --- a/SocketIOClientSwift/SocketTypes.swift +++ b/SocketIOClientSwift/SocketTypes.swift @@ -27,3 +27,4 @@ import Foundation public typealias AckCallback = ([AnyObject]) -> Void public typealias NormalCallback = ([AnyObject], SocketAckEmitter?) -> Void public typealias OnAckCallback = (timeoutAfter: UInt64, callback: AckCallback) -> Void +