From 170b1bc83627c7695f26becadad877af7b8a2fcd Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 23 Feb 2015 15:08:38 -0500 Subject: [PATCH] API CHANGE. See README --- README.md | 50 +++++++++++----------- SwiftIO/SocketAckHandler.swift | 5 --- SwiftIO/SocketEvent.swift | 27 +++++++++--- SwiftIO/SocketEventHandler.swift | 45 +++++++------------- SwiftIO/SocketIOClient.swift | 71 +++++++++++++++----------------- SwiftIO/SwiftRegex.swift | 28 ++++++------- 6 files changed, 110 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 17cf2f4..e227647 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ Socket.IO-Client-Swift ====================== -Socket.IO-client for Swift. Supports ws/wss connections and binary. For socket.io 1.0+ and Swift 1.2 +Socket.IO-client for Swift. Supports ws/wss connections and binary. For socket.io 1.0+ and Swift 1.2. + +For Swift 1.1 use the master branch. Installation ============ @@ -13,11 +15,10 @@ API === Constructor ----------- -`init(socketURL: String, opts[String: AnyObject]? = nil)` - Constructs a new client for the given URL. opts can be omitted (will use default values.) +`init(socketURL: String, opts:[String: AnyObject]? = nil)` - Constructs a new client for the given URL. opts can be omitted (will use default values.) Methods ------- -1. `socket.on(name:String, callback:((data:AnyObject?) -> Void)) -> SocketAckHandler` - Adds a handler for an event. Returns a SocketAckHandler which can be used to ack an event. See example. -2. `socket.onMultipleItems(name:String, callback:((data:NSArray?) -> Void)) -> SocketAckHandler` - Adds a handler for an event that can have multiple items. Items are stored in an array. Returns a SocketAckHandler which can be used to ack an event. See example. +1. `socket.on(name:String, callback:((data:NSArray?, ack:AckEmitter?) -> 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. `socket.emit(event:String, args:AnyObject...)` - Sends a message. Can send multiple args. 4. `socket.emitWithAck(event:String, args:AnyObject...) -> SocketAckHandler` - Sends a message that requests an acknoweldgement from the server. Returns a SocketAckHandler which you can use to add an onAck handler. See example. 5. `socket.connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection. @@ -43,9 +44,9 @@ let socket = SocketIOClient(socketURL: "https://localhost:8080", opts: [ ]) // Socket Events -socket.on("connect") {data in +socket.on("connect") {data, ack in println("socket connected") - + // Sending messages socket.emit("testEcho") @@ -58,9 +59,9 @@ socket.on("connect") {data in true, ["test": "foo"], "bar") } -// Requesting acks, and adding ack args -socket.on("ackEvent") {data in - if let str = data as? String { +// Requesting acks, and responding to acks +socket.on("ackEvent") {data, ack in + if let str = data?[0] as? String { println("Got ackEvent") } @@ -68,36 +69,37 @@ socket.on("ackEvent") {data in println(data) } -}.ackWith("I got your event", "dude") + ack?("Got your event", "dude") +} -socket.on("disconnect") {data in - if let reason = data as? String { +socket.on("disconnect") {data, ack in + if let reason = data?[0] as? String { println("Socket disconnected: \(reason)") } } -socket.on("reconnect") {data in - if let reason = data as? String { +socket.on("reconnect") {data, ack in + if let reason = data?[0] as? String { println("Socket reconnecting: \(reason)") } } -socket.on("reconnectAttempt") {data in - if let triesLeft = data as? Int { +socket.on("reconnectAttempt") {data, ack in + if let triesLeft = data?[0] as? Int { println(triesLeft) } } // End Socket Events -socket.on("jsonTest") {data in - if let json = data as? NSDictionary { +socket.on("jsonTest") {data, ack in + if let json = data?[0] as? NSDictionary { println(json["test"]!) // foo bar } } // Messages that have multiple items are passed // by an array -socket.onMultipleItems("multipleItems") {data in +socket.on("multipleItems") {data, ack in if data == nil { return } @@ -114,16 +116,16 @@ socket.onMultipleItems("multipleItems") {data in println(obj["test"]) } } - + // Recieving binary -socket.on("dataTest") {data in - if let data = data as? NSData { +socket.on("dataTest") {data, ack in + if let data = data?[0] as? NSData { println("data is binary") } } -socket.on("objectDataTest") {data in - if let dict = data as? NSDictionary { +socket.on("objectDataTest") {data, ack in + if let dict = data?[0] as? NSDictionary { if let data = dict["data"] as? NSData { let string = NSString(data: data, encoding: NSUTF8StringEncoding) println("Got data: \(string!)") diff --git a/SwiftIO/SocketAckHandler.swift b/SwiftIO/SocketAckHandler.swift index d3bfe77..5a9d909 100644 --- a/SwiftIO/SocketAckHandler.swift +++ b/SwiftIO/SocketAckHandler.swift @@ -29,7 +29,6 @@ typealias AckCallback = (AnyObject?) -> Void class SocketAckHandler { let ackNum:Int! let event:String! - var ackData:[AnyObject]? var callback:AckCallback? init(event:String, ackNum:Int = 0) { @@ -40,8 +39,4 @@ class SocketAckHandler { func onAck(callback:AckCallback) { self.callback = callback } - - func ackWith(data:AnyObject...) { - self.ackData = data - } } \ No newline at end of file diff --git a/SwiftIO/SocketEvent.swift b/SwiftIO/SocketEvent.swift index c7740c2..59f5639 100644 --- a/SwiftIO/SocketEvent.swift +++ b/SwiftIO/SocketEvent.swift @@ -65,7 +65,7 @@ class SocketEvent { } } - static func createMessageForEvent(event:String, withArgs args:[AnyObject], + class func createMessageForEvent(event:String, withArgs args:[AnyObject], hasBinary:Bool, withDatas datas:Int = 0, toNamespace nsp:String?, wantsAck ack:Int? = nil) -> String { var message:String @@ -104,36 +104,53 @@ class SocketEvent { return self.completeMessage(message, args: args) } - static func createAck(ack:Int, withEvent event:String, withArgs args:[AnyObject], - withAckType ackType:Int, withNsp nsp:String, withBinary binary:Int = 0) -> String { + class func createAck(ack:Int, withArgs args:[AnyObject], withAckType ackType:Int, + withNsp nsp:String, withBinary binary:Int = 0) -> String { var msg:String if ackType == 3 { if nsp == "/" { msg = "43\(ack)[" + if args.count == 0 { + println(msg + "]") + return msg + "]" + } + return self.completeMessage(msg, args: args) } else { msg = "43/\(nsp),\(ack)[" + if args.count == 0 { + return msg + "]" + } + return self.completeMessage(msg, args: args) } } else { if nsp == "/" { msg = "46\(binary)-\(ack)[" + if args.count == 0 { + return msg + "]" + } + return self.completeMessage(msg, args: args) } else { msg = "46\(binary)-/\(nsp),\(ack)[" + if args.count == 0 { + return msg + "]" + } + return self.completeMessage(msg, args: args) } } } - private static func completeMessage(var message:String, args:[AnyObject]) -> String { + private class func completeMessage(var message:String, args:[AnyObject]) -> String { var err:NSError? for arg in args { @@ -142,7 +159,7 @@ class SocketEvent { options: NSJSONWritingOptions(0), error: &err) let jsonString = NSString(data: jsonSend!, encoding: NSUTF8StringEncoding) - message += jsonString! as! String + message += jsonString! as String message += "," continue } diff --git a/SwiftIO/SocketEventHandler.swift b/SwiftIO/SocketEventHandler.swift index a13add6..3fe9204 100644 --- a/SwiftIO/SocketEventHandler.swift +++ b/SwiftIO/SocketEventHandler.swift @@ -22,43 +22,28 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +typealias NormalCallback = (NSArray?, AckEmitter?) -> Void +typealias AckEmitter = (AnyObject...) -> Void + +private func emitAckCallback(socket:SocketIOClient, num:Int, type:Int) -> AckEmitter { + func emitter(items:AnyObject...) { + socket.emitAck(num, withData: items, withAckType: type) + } + + return emitter +} + class SocketEventHandler { - let ack:SocketAckHandler! let event:String! let callback:NormalCallback? - let callbackMult:MultipleCallback? - var multiEvent = false - init(event:String, callback:NormalCallback, ack:SocketAckHandler) { + init(event:String, callback:NormalCallback) { self.event = event self.callback = callback - self.callbackMult = nil - self.ack = ack } - init(event:String, callback:MultipleCallback, ack:SocketAckHandler) { - self.event = event - self.callbackMult = callback - self.callback = nil - self.multiEvent = true - self.ack = ack - } - - func executeCallback(item:AnyObject?, items:NSArray? = nil) { - if self.multiEvent { - if items != nil { - callbackMult?(items) - } else if item != nil { - callbackMult?([item!]) - } else { - callbackMult?(nil) - } - } else { - if items != nil { - callback?(items) - } else { - callback?(item) - } - } + func executeCallback(_ items:NSArray? = nil, withAck ack:Int? = nil, withAckType type:Int? = nil, + withSocket socket:SocketIOClient? = nil) { + callback?(items, ack != nil ? emitAckCallback(socket!, ack!, type!) : nil) } } \ No newline at end of file diff --git a/SwiftIO/SocketIOClient.swift b/SwiftIO/SocketIOClient.swift index 6065018..2aa1197 100644 --- a/SwiftIO/SocketIOClient.swift +++ b/SwiftIO/SocketIOClient.swift @@ -24,9 +24,6 @@ import Foundation -typealias NormalCallback = (AnyObject?) -> Void -typealias MultipleCallback = (NSArray?) -> Void - class SocketIOClient: NSObject, SRWebSocketDelegate { let socketURL:NSMutableString! let ackQueue = dispatch_queue_create("ackQueue".cStringUsingEncoding(NSUTF8StringEncoding), @@ -57,9 +54,8 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { if mutURL["https://"].matches().count != 0 { self.secure = true - } else { - self.secure = false } + mutURL = mutURL["http://"] ~= "" mutURL = mutURL["https://"] ~= "" @@ -198,7 +194,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } // If the server wants to know that the client received data - private func emitAck(ack:Int, withEvent event:String, withData data:[AnyObject]?, withAckType ackType:Int) { + func emitAck(ack:Int, withData data:[AnyObject]?, withAckType ackType:Int) { dispatch_async(self.ackQueue) {[weak self] in if self == nil || !self!.connected || data == nil { return @@ -209,20 +205,20 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { if !hasBinary { if self?.nsp == nil { - str = SocketEvent.createAck(ack, withEvent: event, withArgs: items, + str = SocketEvent.createAck(ack, withArgs: items, withAckType: 3, withNsp: "/") } else { - str = SocketEvent.createAck(ack, withEvent: event, withArgs: items, + str = SocketEvent.createAck(ack, withArgs: items, withAckType: 3, withNsp: self!.nsp!) } self?.io?.send(str) } else { if self?.nsp == nil { - str = SocketEvent.createAck(ack, withEvent: event, withArgs: items, + str = SocketEvent.createAck(ack, withArgs: items, withAckType: 6, withNsp: "/", withBinary: emitDatas.count) } else { - str = SocketEvent.createAck(ack, withEvent: event, withArgs: items, + str = SocketEvent.createAck(ack, withArgs: items, withAckType: 6, withNsp: self!.nsp!, withBinary: emitDatas.count) } @@ -256,16 +252,27 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { for handler in self.handlers { if handler.event == event { if data is NSArray { - handler.executeCallback(nil, items: (data as! NSArray)) if ack != nil { - self.emitAck(ack!, withEvent: event, - withData: handler.ack.ackData, withAckType: ackType) + handler.executeCallback(data as? NSArray, withAck: ack!, + withAckType: ackType, withSocket: self) + } else { + handler.executeCallback(data as? NSArray) } } else { - handler.executeCallback(data) + + // Trying to do a ternary expression in the executeCallback method + // seemed to crash Swift + var dataArr:NSArray? = nil + + if let data:AnyObject = data { + dataArr = [data] + } + if ack != nil { - self.emitAck(ack!, withEvent: event, - withData: handler.ack.ackData, withAckType: ackType) + handler.executeCallback(dataArr, withAck: ack!, + withAckType: ackType, withSocket: self) + } else { + handler.executeCallback(dataArr) } } } @@ -280,21 +287,9 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } // Adds handler for single arg message - func on(name:String, callback:NormalCallback) -> SocketAckHandler { - let ackHandler = SocketAckHandler(event: name) - let handler = SocketEventHandler(event: name, callback: callback, ack: ackHandler) + func on(name:String, callback:NormalCallback) { + let handler = SocketEventHandler(event: name, callback: callback) self.handlers.append(handler) - - return ackHandler - } - - // Adds handler for multiple arg message - func onMultipleItems(name:String, callback:MultipleCallback) -> SocketAckHandler { - let ackHandler = SocketAckHandler(event: name) - let handler = SocketEventHandler(event: name, callback: callback, ack: ackHandler) - self.handlers.append(handler) - - return ackHandler } // Opens the connection to the socket @@ -303,7 +298,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } // Parse an NSArray looking for binary data - private static func parseArray(arr:NSArray, var placeholders:Int) -> (NSArray, Bool, [NSData]) { + private class func parseArray(arr:NSArray, var placeholders:Int) -> (NSArray, Bool, [NSData]) { var replacementArr = [AnyObject](count: arr.count, repeatedValue: 1) var hasBinary = false var arrayDatas = [NSData]() @@ -352,7 +347,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } // Parses data for events - static func parseData(data:String?) -> AnyObject? { + class func parseData(data:String?) -> AnyObject? { if data == nil { return nil } @@ -370,7 +365,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { return parsed } - private static func parseEmitArgs(args:[AnyObject]) -> ([AnyObject], Bool, [NSData]) { + private class func parseEmitArgs(args:[AnyObject]) -> ([AnyObject], Bool, [NSData]) { var items = [AnyObject](count: args.count, repeatedValue: 1) var numberOfPlaceholders = -1 var hasBinary = false @@ -424,7 +419,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } // Parses a NSDictionary, looking for NSData objects - private static func parseNSDictionary(dict:NSDictionary, var placeholders:Int) -> (NSDictionary, Bool, [NSData]) { + private class func parseNSDictionary(dict:NSDictionary, var placeholders:Int) -> (NSDictionary, Bool, [NSData]) { var returnDict = NSMutableDictionary() var hasBinary = false if placeholders == -1 { @@ -589,7 +584,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } } else if messageGroups[1].hasPrefix("43") { let arr = Array(messageGroups[1]) - let ackNum:String + var ackNum:String let nsp = messageGroups[2] if nsp == "" && self.nsp != nil { @@ -671,7 +666,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] ~= "\"~~$2\"" - let mes:SocketEvent + var mes:SocketEvent if ackNum == "" { mes = SocketEvent(event: event, args: placeholdersRemoved, placeholders: numberOfPlaceholders.toInt()!) @@ -685,8 +680,8 @@ class SocketIOClient: NSObject, SRWebSocketDelegate { } else if binaryGroup[1].hasPrefix("46") { let messageType = RegexMutable(binaryGroup[1]) let numberOfPlaceholders = (messageType["46"] ~= "") as String - let ackNum:String - let nsp:String + var ackNum:String + var nsp:String if binaryGroup[3] == "" { ackNum = binaryGroup[2] diff --git a/SwiftIO/SwiftRegex.swift b/SwiftIO/SwiftRegex.swift index 360d051..474f6c5 100644 --- a/SwiftIO/SwiftRegex.swift +++ b/SwiftIO/SwiftRegex.swift @@ -60,15 +60,15 @@ public class SwiftRegex: NSObject, BooleanType { } public func range(options: NSMatchingOptions = nil) -> NSRange { - return regex.rangeOfFirstMatchInString(target as! String, options: nil, range: targetRange) + return regex.rangeOfFirstMatchInString(target as String, options: nil, range: targetRange) } public func match(options: NSMatchingOptions = nil) -> String! { - return substring(range(options: options)) as! String + return substring(range(options: options)) as String } public func groups(options: NSMatchingOptions = nil) -> [String]! { - return groupsForMatch( regex.firstMatchInString(target as! String, options: options, range: targetRange) ) + return groupsForMatch( regex.firstMatchInString(target as String, options: options, range: targetRange) ) } func groupsForMatch(match: NSTextCheckingResult!) -> [String]! { @@ -95,7 +95,7 @@ public class SwiftRegex: NSObject, BooleanType { if let mutableTarget = target as? NSMutableString { for match in matchResults()!.reverse() { let replacement = regex.replacementStringForResult( match, - inString: target as! String, offset: 0, template: newValue ) + inString: target as String, offset: 0, template: newValue ) mutableTarget.replaceCharactersInRange(match.rangeAtIndex(groupno), withString: replacement) } } else { @@ -105,7 +105,7 @@ public class SwiftRegex: NSObject, BooleanType { } func matchResults(options: NSMatchingOptions = nil) -> [NSTextCheckingResult]? { - let matches = regex.matchesInString(target as! String, options: options, range: targetRange) + let matches = regex.matchesInString(target as String, options: options, range: targetRange) as? [NSTextCheckingResult] if matches != nil { @@ -130,8 +130,8 @@ public class SwiftRegex: NSObject, BooleanType { public func dictionary(options: NSMatchingOptions = nil) -> Dictionary { var out = Dictionary() for match in matchResults(options: options)! { - out[substring(match.rangeAtIndex(1)) as! String] = - substring(match.rangeAtIndex(2)) as? String + out[substring(match.rangeAtIndex(1)) as String] = + substring(match.rangeAtIndex(2)) as String } return out } @@ -141,16 +141,16 @@ public class SwiftRegex: NSObject, BooleanType { let out = NSMutableString() var pos = 0 - regex.enumerateMatchesInString(target as! String, options: options, range: targetRange ) { + regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) { (match: NSTextCheckingResult!, flags: NSMatchingFlags, stop: UnsafeMutablePointer) in let matchRange = match.range - out.appendString( self.substring( NSRange(location:pos, length:matchRange.location-pos) ) as! String ) + out.appendString( self.substring( NSRange(location:pos, length:matchRange.location-pos) ) as String ) out.appendString( substitution(match, stop) ) pos = matchRange.location + matchRange.length } - out.appendString( substring( NSRange(location:pos, length:targetRange.length-pos) ) as! String ) + out.appendString( substring( NSRange(location:pos, length:targetRange.length-pos) ) as String ) if let mutableTarget = target as? NSMutableString { mutableTarget.setString(out as String) @@ -215,13 +215,13 @@ extension String { } public func RegexMutable(string: NSString) -> NSMutableString { - return NSMutableString(string:string as! String) + return NSMutableString(string:string as String) } public func ~= (left: SwiftRegex, right: String) -> NSMutableString { return left.substituteMatches({match, stop in return left.regex.replacementStringForResult( match, - inString: left.target as! String, offset: 0, template: right ) + inString: left.target as String, offset: 0, template: right ) }, options: nil) } @@ -234,7 +234,7 @@ public func ~= (left: SwiftRegex, right: [String]) -> NSMutableString { } return left.regex.replacementStringForResult( match, - inString: left.target as! String, offset: 0, template: right[matchNumber-1] ) + inString: left.target as String, offset: 0, template: right[matchNumber-1] ) }, options: nil) } @@ -242,7 +242,7 @@ public func ~= (left: SwiftRegex, right: (String) -> String) -> NSMutableString // return right(left.substring(match.range)) return left.substituteMatches( {match, stop -> String in - right(left.substring(match.range) as! String) + right(left.substring(match.range) as String) }, options: nil) }