├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CONTRIBUTORS.md ├── LICENSE ├── README.md ├── SocketIO.h ├── SocketIO.m ├── SocketIOJSONSerialization.h ├── SocketIOJSONSerialization.m ├── SocketIOPacket.h ├── SocketIOPacket.m ├── SocketIOTransport.h ├── SocketIOTransportWebsocket.h ├── SocketIOTransportWebsocket.m ├── SocketIOTransportXHR.h ├── SocketIOTransportXHR.m ├── SocketTesterARC.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── SocketTesterARC ├── AppDelegate.h ├── AppDelegate.m ├── SocketTesterARC-Info.plist ├── SocketTesterARC-Prefix.pch ├── ViewController.h ├── ViewController.m ├── en.lproj │ ├── InfoPlist.strings │ └── ViewController.xib └── main.m └── submodules └── .gitignore /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | *xcuserdata* 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodules/socket-rocket"] 2 | path = submodules/socket-rocket 3 | url = https://github.com/square/SocketRocket.git 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.5.2 (2014-03-23) 2 | 3 | - check HTTP status code of NSURLConnection responses during xhr polling transport 4 | 5 | 6 | ## 0.5.1 (2014-03-14) 7 | 8 | - add method to pass cookies on handshake 9 | - distinguish between handshake failed and unauthorized handshake 10 | 11 | 12 | ## 0.5 (2014-02-21) 13 | 14 | - finally remove deprecated delegate methods 15 | - remove external JSON frameworks 16 | 17 | 18 | ## 0.4.1 (2013-11-18) 19 | 20 | - fix unix timecode bug in handshake url. close #118. 21 | - Instantiate errorInfo NSMutableDictionary using mutableCopy as suggested by Elshad. close #125. 22 | - introduce closed flag to XHR transport. fix #130. 23 | - Changed delegates from unsafe_unretained to weak 24 | - Fix improper use of NSLocalizedDescriptionKey. 25 | 26 | 27 | ## 0.4.0.1 (2013-09-19) 28 | 29 | - bugfix for namespace param error 30 | 31 | 32 | ## 0.4 (2013-07-18) 33 | 34 | - update example code to also include the new setResourceName: method 35 | - allow socket.io resource to be renamed from outside. close #80. 36 | - cleaned up URL schemas and their usage 37 | - try forced disconnect in SocketTester example 38 | - adjust the forced disconnect method a bit 39 | - change deployment target to iOS 5 (because socket-rocket needs it and we're using __weak now) 40 | - update submodules 41 | - SocketIO: don't use NSURLConnection delegate property in -dealloc - not available without BlocksKit 42 | - Synchronous disconnect 43 | - Fixed for sending events before socket is connected 44 | - Ensure to cleanup properly in -disconnect & -dealloc - fixes crashes 45 | - Add initial connection timeout 46 | - Fixed disconnect error loop 47 | - Changed timeout timer from NSTimer to GCD timer to avoid retain cycle. 48 | 49 | 50 | ## 0.3.3 (2013-04-25) 51 | 52 | - Payloads cause disconnects. fixes #65 53 | - Fixes inability to reconnect as described in #76 54 | - Send all arguments to the callback, not just the first one. fixes #85 55 | 56 | 57 | ## 0.3.2 (2013-02-06) 58 | 59 | - Suppress deprecation warning (it's already checked with respondsToSelector) 60 | - cleanup + SR submodule update fixes #70 61 | - Fixed bug where SocketIOTransportWebsocket didn't clear the delegate on the SRWebSocket. 62 | 63 | 64 | ## 0.3.1 (2012-12-26) 65 | 66 | - fixes connect/disconnect problems. close #46 67 | 68 | 69 | ## 0.3 (2012-12-24) 70 | 71 | - added long polling. fixed #8. 72 | - handshake response data check updated. fixes #62. 73 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | #Contributors 2 | 3 | Many thanks to the following people for helping me with this: 4 | 5 | - [mennopruijssers](https://github.com/mennopruijssers) 6 | - [samlown](https://github.com/samlown) 7 | - [DanLite](https://github.com/DanLite) 8 | - [bnadim](https://github.com/bnadim) 9 | - [kayleg](https://github.com/kayleg) 10 | - [psineur](https://github.com/psineur) 11 | - [dgthistle](https://github.com/dgthistle) 12 | - [paiv](https://github.com/paiv) 13 | - [hongkongkiwi](https://github.com/hongkongkiwi) 14 | - [antonholmquist](https://github.com/antonholmquist) 15 | - [spesholized](https://github.com/spesholized) 16 | - [insanehunter](https://github.com/insanehunter) 17 | - [RevCBH](https://github.com/RevCBH) 18 | - [elwerene](https://github.com/elwerene) 19 | - [MichaelScaria](https://github.com/MichaelScaria) 20 | - [beepscore](https://github.com/beepscore) 21 | - [progeddog](https://github.com/progeddog) 22 | - [bridger](https://github.com/bridger) 23 | - [YannickL](https://github.com/YannickL) 24 | - [taiyangc](https://github.com/taiyangc) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-12 Philipp Kyeck 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **The current version of this library does not support socket.io v1.0. 2 | So if you want to use socket.io-objc, please fall back to v0.9.x.** 3 | 4 | Today (15/03/09) the Socket.io guys [announced their own iOS library](http://socket.io/blog/socket-io-on-ios/) - grab it while it's still hot: 5 | [github.com/socketio/socket.io-client-swift](https://github.com/socketio/socket.io-client-swift) 6 | 7 | --- 8 | 9 | # Socket.IO / Objective C Library 10 | 11 | Interface to communicate between Objective C and [Socket.IO](http://socket.io/) 12 | with the help of websockets or [Long-Polling](http://en.wikipedia.org/wiki/Push_technology#Long_polling). Originally based on fpotter's [socketio-cocoa](https://github.com/fpotter/socketio-cocoa) 13 | it uses other libraries/classes like 14 | 15 | * [SocketRocket](https://github.com/square/SocketRocket) 16 | Look [here](https://github.com/square/SocketRocket#installing-ios) for further instructions how to use/install SocketRocket. 17 | 18 | 19 | ## Requirements 20 | 21 | As of version 0.4, this library requires at least OS X 10.7 or iOS 5.0. 22 | Because of this, we were able to remove the external JSON frameworks in v0.5 and only rely on iOS' own `NSJSONSerialization`. 23 | 24 | 25 | ## Usage 26 | 27 | The easiest way to connect to your Socket.IO / node.js server is 28 | 29 | ``` objective-c 30 | SocketIO *socketIO = [[SocketIO alloc] initWithDelegate:self]; 31 | [socketIO connectToHost:@"localhost" onPort:3000]; 32 | ``` 33 | 34 | If required, additional parameters can be included in the handshake by adding an `NSDictionary` to the `withParams` option: 35 | 36 | ``` objective-c 37 | [socketIO connectToHost:@"localhost" 38 | onPort:3000 39 | withParams:@{@"auth_token":@"1234"}]; 40 | ``` 41 | 42 | A namespace can also be defined in the connection details: 43 | 44 | ``` objective-c 45 | [socketIO connectToHost:@"localhost" onPort:3000 withParams:nil withNamespace:@"/users"]; 46 | ``` 47 | 48 | There are different methods to send data to the server 49 | 50 | ``` objective-c 51 | - (void) sendMessage:(NSString *)data; 52 | - (void) sendMessage:(NSString *)data withAcknowledge:(SocketIOCallback)function; 53 | - (void) sendJSON:(NSDictionary *)data; 54 | - (void) sendJSON:(NSDictionary *)data withAcknowledge:(SocketIOCallback)function; 55 | - (void) sendEvent:(NSString *)eventName withData:(NSDictionary *)data; 56 | - (void) sendEvent:(NSString *)eventName withData:(NSDictionary *)data andAcknowledge:(SocketIOCallback)function; 57 | ``` 58 | 59 | So you could send a normal Message like this 60 | 61 | ``` objective-c 62 | [socketIO sendMessage:@"hello world"]; 63 | ``` 64 | 65 | or an Event (including some data) like this 66 | 67 | ``` objective-c 68 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 69 | [dict setObject:@"test1" forKey:@"key1"]; 70 | [dict setObject:@"test2" forKey:@"key2"]; 71 | 72 | [socketIO sendEvent:@"welcome" withData:dict]; 73 | ``` 74 | 75 | If you want the server to acknowledge your Message/Event you would also pass a SocketIOCallback block 76 | 77 | ``` objective-c 78 | SocketIOCallback cb = ^(id argsData) { 79 | NSDictionary *response = argsData; 80 | // do something with response 81 | }; 82 | [socketIO sendEvent:@"welcomeAck" withData:dict andAcknowledge:cb]; 83 | ``` 84 | 85 | All delegate methods are optional - you could implement the following 86 | 87 | ``` objective-c 88 | - (void) socketIODidConnect:(SocketIO *)socket; 89 | - (void) socketIODidDisconnect:(SocketIO *)socket disconnectedWithError:(NSError *)error; 90 | - (void) socketIO:(SocketIO *)socket didReceiveMessage:(SocketIOPacket *)packet; 91 | - (void) socketIO:(SocketIO *)socket didReceiveJSON:(SocketIOPacket *)packet; 92 | - (void) socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet; 93 | - (void) socketIO:(SocketIO *)socket didSendMessage:(SocketIOPacket *)packet; 94 | - (void) socketIO:(SocketIO *)socket onError:(NSError *)error; 95 | ``` 96 | 97 | To process an incoming `message` or `event` just 98 | 99 | ``` objective-c 100 | // message delegate 101 | - (void) socketIO:(SocketIO *)socket didReceiveMessage:(SocketIOPacket *)packet 102 | { 103 | NSLog(@"didReceiveMessage >>> data: %@", packet.data); 104 | } 105 | 106 | // event delegate 107 | - (void) socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet 108 | { 109 | NSLog(@"didReceiveEvent >>> data: %@", packet.data); 110 | } 111 | ``` 112 | 113 | ## Usage with OS X 114 | 115 | Running the socket.io-objc library with OS X requires some minor changes: 116 | 117 | - you have to use the SocketRocket.framework for OSX instead of just the submodule 118 | see: [SocketRocket's Installing OS X](https://github.com/square/SocketRocket#installing-os-x) 119 | (best way I got this to work was as a subproject and I didn't have to add the "copy file" stuff) 120 | 121 | - when using the osx-framework, you have to fix the import-statement in SocketIOTransportWebsocket.h 122 | 123 | ``` objective-c 124 | // replace 125 | #import SRWebSocket.h 126 | 127 | // with 128 | #import 129 | ``` 130 | 131 | ## Authors 132 | 133 | Initial project by Philipp Kyeck . 134 | Additional support from these [amazing people](https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md). 135 | 136 | ## License 137 | 138 | (The MIT License) 139 | 140 | Copyright (c) 2011-14 Philipp Kyeck 141 | 142 | Permission is hereby granted, free of charge, to any person obtaining a copy 143 | of this software and associated documentation files (the "Software"), to deal 144 | in the Software without restriction, including without limitation the rights 145 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 146 | copies of the Software, and to permit persons to whom the Software is 147 | furnished to do so, subject to the following conditions: 148 | 149 | The above copyright notice and this permission notice shall be included in 150 | all copies or substantial portions of the Software. 151 | 152 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 153 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 154 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 155 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 156 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 157 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 158 | THE SOFTWARE. 159 | -------------------------------------------------------------------------------- /SocketIO.h: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIO.h 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import 22 | 23 | #import "SocketIOTransport.h" 24 | 25 | @class SocketIO; 26 | @class SocketIOPacket; 27 | 28 | typedef void(^SocketIOCallback)(id argsData); 29 | 30 | extern NSString* const SocketIOError; 31 | 32 | typedef enum { 33 | SocketIOServerRespondedWithInvalidConnectionData = -1, 34 | SocketIOServerRespondedWithDisconnect = -2, 35 | SocketIOHeartbeatTimeout = -3, 36 | SocketIOWebSocketClosed = -4, 37 | SocketIOTransportsNotSupported = -5, 38 | SocketIOHandshakeFailed = -6, 39 | SocketIODataCouldNotBeSend = -7, 40 | SocketIOUnauthorized = -8 41 | } SocketIOErrorCodes; 42 | 43 | 44 | @protocol SocketIODelegate 45 | @optional 46 | - (void) socketIODidConnect:(SocketIO *)socket; 47 | - (void) socketIODidDisconnect:(SocketIO *)socket disconnectedWithError:(NSError *)error; 48 | - (void) socketIO:(SocketIO *)socket didReceiveMessage:(SocketIOPacket *)packet; 49 | - (void) socketIO:(SocketIO *)socket didReceiveJSON:(SocketIOPacket *)packet; 50 | - (void) socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet; 51 | - (void) socketIO:(SocketIO *)socket didSendMessage:(SocketIOPacket *)packet; 52 | - (void) socketIO:(SocketIO *)socket onError:(NSError *)error; 53 | @end 54 | 55 | 56 | @interface SocketIO : NSObject 57 | { 58 | NSString *_host; 59 | NSInteger _port; 60 | NSString *_sid; 61 | NSString *_endpoint; 62 | NSDictionary *_params; 63 | 64 | __weak id _delegate; 65 | 66 | NSObject *_transport; 67 | 68 | BOOL _isConnected; 69 | BOOL _isConnecting; 70 | BOOL _useSecure; 71 | 72 | NSArray *_cookies; 73 | 74 | NSURLConnection *_handshake; 75 | 76 | // heartbeat 77 | NSTimeInterval _heartbeatTimeout; 78 | dispatch_source_t _timeout; 79 | 80 | NSMutableArray *_queue; 81 | 82 | // acknowledge 83 | NSMutableDictionary *_acks; 84 | NSInteger _ackCount; 85 | 86 | // http request 87 | NSMutableData *_httpRequestData; 88 | 89 | // get all arguments from ack? (https://github.com/pkyeck/socket.IO-objc/pull/85) 90 | BOOL _returnAllDataFromAck; 91 | } 92 | 93 | @property (nonatomic, readonly) NSString *host; 94 | @property (nonatomic, readonly) NSInteger port; 95 | @property (nonatomic, readonly) NSString *sid; 96 | @property (nonatomic, readonly) NSTimeInterval heartbeatTimeout; 97 | @property (nonatomic) BOOL useSecure; 98 | @property (nonatomic) NSArray *cookies; 99 | @property (nonatomic, readonly) BOOL isConnected, isConnecting; 100 | @property (nonatomic, weak) id delegate; 101 | @property (nonatomic) BOOL returnAllDataFromAck; 102 | 103 | - (id) initWithDelegate:(id)delegate; 104 | - (void) connectToHost:(NSString *)host onPort:(NSInteger)port; 105 | - (void) connectToHost:(NSString *)host onPort:(NSInteger)port withParams:(NSDictionary *)params; 106 | - (void) connectToHost:(NSString *)host onPort:(NSInteger)port withParams:(NSDictionary *)params withNamespace:(NSString *)endpoint; 107 | - (void) connectToHost:(NSString *)host onPort:(NSInteger)port withParams:(NSDictionary *)params withNamespace:(NSString *)endpoint withConnectionTimeout: (NSTimeInterval) connectionTimeout; 108 | 109 | - (void) disconnect; 110 | - (void) disconnectForced; 111 | 112 | - (void) sendMessage:(NSString *)data; 113 | - (void) sendMessage:(NSString *)data withAcknowledge:(SocketIOCallback)function; 114 | - (void) sendJSON:(NSDictionary *)data; 115 | - (void) sendJSON:(NSDictionary *)data withAcknowledge:(SocketIOCallback)function; 116 | - (void) sendEvent:(NSString *)eventName withData:(id)data; 117 | - (void) sendEvent:(NSString *)eventName withData:(id)data andAcknowledge:(SocketIOCallback)function; 118 | - (void) sendAcknowledgement:(NSString*)pId withArgs:(NSArray *)data; 119 | 120 | - (void) setResourceName:(NSString *)name; 121 | 122 | @end -------------------------------------------------------------------------------- /SocketIO.m: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIO.m 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import "SocketIO.h" 22 | #import "SocketIOPacket.h" 23 | #import "SocketIOJSONSerialization.h" 24 | 25 | #ifdef DEBUG 26 | #define DEBUG_LOGS 1 27 | #define DEBUG_CERTIFICATE 1 28 | #else 29 | #define DEBUG_LOGS 0 30 | #define DEBUG_CERTIFICATE 0 31 | #endif 32 | 33 | #if DEBUG_LOGS 34 | #define DEBUGLOG(...) NSLog(__VA_ARGS__) 35 | #else 36 | #define DEBUGLOG(...) 37 | #endif 38 | 39 | static NSString* kResourceName = @"socket.io"; 40 | static NSString* kHandshakeURL = @"%@://%@%@/%@/1/?t=%.0f%@"; 41 | static NSString* kForceDisconnectURL = @"%@://%@%@/%@/1/xhr-polling/%@?disconnect"; 42 | 43 | float const defaultConnectionTimeout = 10.0f; 44 | 45 | NSString* const SocketIOError = @"SocketIOError"; 46 | NSString* const SocketIOException = @"SocketIOException"; 47 | 48 | # pragma mark - 49 | # pragma mark SocketIO's private interface 50 | 51 | @interface SocketIO (Private) 52 | 53 | - (NSArray*) arrayOfCaptureComponentsMatchedByRegex:(NSString*)regex; 54 | 55 | - (void) setTimeout; 56 | - (void) onTimeout; 57 | 58 | - (void) onConnect:(SocketIOPacket *)packet; 59 | - (void) onDisconnect:(NSError *)error; 60 | 61 | - (void) sendDisconnect; 62 | - (void) sendHearbeat; 63 | - (void) send:(SocketIOPacket *)packet; 64 | 65 | - (NSString *) addAcknowledge:(SocketIOCallback)function; 66 | - (void) removeAcknowledgeForKey:(NSString *)key; 67 | - (NSMutableArray*) getMatchesFrom:(NSString*)data with:(NSString*)regex; 68 | 69 | @end 70 | 71 | # pragma mark - 72 | # pragma mark SocketIO implementation 73 | 74 | @implementation SocketIO 75 | 76 | @synthesize isConnected = _isConnected, 77 | isConnecting = _isConnecting, 78 | useSecure = _useSecure, 79 | cookies = _cookies, 80 | delegate = _delegate, 81 | heartbeatTimeout = _heartbeatTimeout, 82 | returnAllDataFromAck = _returnAllDataFromAck; 83 | 84 | - (id) initWithDelegate:(id)delegate 85 | { 86 | self = [super init]; 87 | if (self) { 88 | _delegate = delegate; 89 | _queue = [[NSMutableArray alloc] init]; 90 | _ackCount = 0; 91 | _acks = [[NSMutableDictionary alloc] init]; 92 | _returnAllDataFromAck = NO; 93 | } 94 | return self; 95 | } 96 | 97 | - (void) connectToHost:(NSString *)host onPort:(NSInteger)port 98 | { 99 | [self connectToHost:host onPort:port withParams:nil withNamespace:@"" withConnectionTimeout:defaultConnectionTimeout]; 100 | } 101 | 102 | - (void) connectToHost:(NSString *)host onPort:(NSInteger)port withParams:(NSDictionary *)params 103 | { 104 | [self connectToHost:host onPort:port withParams:params withNamespace:@"" withConnectionTimeout:defaultConnectionTimeout]; 105 | } 106 | 107 | - (void) connectToHost:(NSString *)host 108 | onPort:(NSInteger)port 109 | withParams:(NSDictionary *)params 110 | withNamespace:(NSString *)endpoint 111 | { 112 | [self connectToHost:host onPort:port withParams:params withNamespace:endpoint withConnectionTimeout:defaultConnectionTimeout]; 113 | } 114 | 115 | - (void) connectToHost:(NSString *)host 116 | onPort:(NSInteger)port 117 | withParams:(NSDictionary *)params 118 | withNamespace:(NSString *)endpoint 119 | withConnectionTimeout:(NSTimeInterval)connectionTimeout 120 | { 121 | if (!_isConnected && !_isConnecting) { 122 | _isConnecting = YES; 123 | 124 | _host = host; 125 | _port = port; 126 | _params = params; 127 | _endpoint = [endpoint copy]; 128 | 129 | // create a query parameters string 130 | NSMutableString *query = [[NSMutableString alloc] initWithString:@""]; 131 | [params enumerateKeysAndObjectsUsingBlock: ^(id key, id value, BOOL *stop) { 132 | [query appendFormat:@"&%@=%@", key, value]; 133 | }]; 134 | 135 | // do handshake via HTTP request 136 | NSString *protocol = _useSecure ? @"https" : @"http"; 137 | NSString *port = _port ? [NSString stringWithFormat:@":%d", _port] : @""; 138 | NSTimeInterval time = [[NSDate date] timeIntervalSince1970] * 1000; 139 | NSString *handshakeUrl = [NSString stringWithFormat:kHandshakeURL, protocol, _host, port, kResourceName, time, query]; 140 | 141 | DEBUGLOG(@"Connecting to socket with URL: %@", handshakeUrl); 142 | query = nil; 143 | 144 | // make a request 145 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:handshakeUrl] 146 | cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData 147 | timeoutInterval:connectionTimeout]; 148 | 149 | if (_cookies != nil) { 150 | DEBUGLOG(@"Adding cookie(s): %@", [_cookies description]); 151 | NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:_cookies]; 152 | [request setAllHTTPHeaderFields:headers]; 153 | } 154 | 155 | [request setHTTPShouldHandleCookies:YES]; 156 | 157 | _handshake = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; 158 | [_handshake scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 159 | [_handshake start]; 160 | 161 | if (_handshake) { 162 | _httpRequestData = [NSMutableData data]; 163 | } 164 | else { 165 | // connection failed 166 | [self connection:_handshake didFailWithError:nil]; 167 | } 168 | } 169 | } 170 | 171 | - (void) disconnect 172 | { 173 | if (_isConnected) { 174 | [self sendDisconnect]; 175 | } 176 | else if (_isConnecting) { 177 | [_handshake cancel]; 178 | [self onDisconnect: nil]; 179 | } 180 | } 181 | 182 | - (void) disconnectForced 183 | { 184 | NSString *protocol = [self useSecure] ? @"https" : @"http"; 185 | NSString *port = _port ? [NSString stringWithFormat:@":%d", _port] : @""; 186 | NSString *urlString = [NSString stringWithFormat:kForceDisconnectURL, protocol, _host, port, kResourceName, _sid]; 187 | NSURL *url = [NSURL URLWithString:urlString]; 188 | DEBUGLOG(@"Force disconnect at: %@", urlString); 189 | 190 | NSURLRequest *request = [NSURLRequest requestWithURL:url]; 191 | NSError *error = nil; 192 | NSHTTPURLResponse *response = nil; 193 | 194 | [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 195 | 196 | if (error || [response statusCode] != 200) { 197 | DEBUGLOG(@"Error during disconnect: %@", error); 198 | } 199 | 200 | [self onDisconnect:error]; 201 | } 202 | 203 | - (void) sendMessage:(NSString *)data 204 | { 205 | [self sendMessage:data withAcknowledge:nil]; 206 | } 207 | 208 | - (void) sendMessage:(NSString *)data withAcknowledge:(SocketIOCallback)function 209 | { 210 | SocketIOPacket *packet = [[SocketIOPacket alloc] initWithType:@"message"]; 211 | packet.data = data; 212 | packet.pId = [self addAcknowledge:function]; 213 | [self send:packet]; 214 | } 215 | 216 | - (void) sendJSON:(NSDictionary *)data 217 | { 218 | [self sendJSON:data withAcknowledge:nil]; 219 | } 220 | 221 | - (void) sendJSON:(NSDictionary *)data withAcknowledge:(SocketIOCallback)function 222 | { 223 | SocketIOPacket *packet = [[SocketIOPacket alloc] initWithType:@"json"]; 224 | packet.data = [SocketIOJSONSerialization JSONStringFromObject:data error:nil]; 225 | packet.pId = [self addAcknowledge:function]; 226 | [self send:packet]; 227 | } 228 | 229 | - (void) sendEvent:(NSString *)eventName withData:(id)data 230 | { 231 | [self sendEvent:eventName withData:data andAcknowledge:nil]; 232 | } 233 | 234 | - (void) sendEvent:(NSString *)eventName withData:(id)data andAcknowledge:(SocketIOCallback)function 235 | { 236 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:eventName forKey:@"name"]; 237 | 238 | // do not require arguments 239 | if (data != nil) { 240 | [dict setObject:[NSArray arrayWithObject:data] forKey:@"args"]; 241 | } 242 | 243 | SocketIOPacket *packet = [[SocketIOPacket alloc] initWithType:@"event"]; 244 | packet.data = [SocketIOJSONSerialization JSONStringFromObject:dict error:nil]; 245 | packet.pId = [self addAcknowledge:function]; 246 | if (function) { 247 | packet.ack = @"data"; 248 | } 249 | [self send:packet]; 250 | } 251 | 252 | - (void) sendAcknowledgement:(NSString *)pId withArgs:(NSArray *)data 253 | { 254 | SocketIOPacket *packet = [[SocketIOPacket alloc] initWithType:@"ack"]; 255 | packet.data = [SocketIOJSONSerialization JSONStringFromObject:data error:nil]; 256 | packet.pId = pId; 257 | packet.ack = @"data"; 258 | 259 | [self send:packet]; 260 | } 261 | 262 | - (void) setResourceName:(NSString *)name 263 | { 264 | kResourceName = [name copy]; 265 | } 266 | 267 | # pragma mark - 268 | # pragma mark private methods 269 | 270 | - (void) sendDisconnect 271 | { 272 | SocketIOPacket *packet = [[SocketIOPacket alloc] initWithType:@"disconnect"]; 273 | [self send:packet]; 274 | [self onDisconnect:nil]; 275 | } 276 | 277 | - (void) sendConnect 278 | { 279 | SocketIOPacket *packet = [[SocketIOPacket alloc] initWithType:@"connect"]; 280 | [self send:packet]; 281 | } 282 | 283 | - (void) sendHeartbeat 284 | { 285 | SocketIOPacket *packet = [[SocketIOPacket alloc] initWithType:@"heartbeat"]; 286 | [self send:packet]; 287 | } 288 | 289 | - (void) send:(SocketIOPacket *)packet 290 | { 291 | if (![self isConnected] && ![self isConnecting]) { 292 | DEBUGLOG(@"Already disconnected!"); 293 | return; 294 | } 295 | DEBUGLOG(@"send()"); 296 | NSNumber *type = [packet typeAsNumber]; 297 | NSMutableArray *encoded = [NSMutableArray arrayWithObject:type]; 298 | 299 | NSString *pId = packet.pId != nil ? packet.pId : @""; 300 | if ([packet.ack isEqualToString:@"data"]) { 301 | pId = [pId stringByAppendingString:@"+"]; 302 | } 303 | 304 | // Do not write pid for acknowledgements 305 | if ([type intValue] != 6) { 306 | [encoded addObject:pId]; 307 | } 308 | 309 | // Add the end point for the namespace to be used, as long as it is not 310 | // an ACK, heartbeat, or disconnect packet 311 | if ([type intValue] != 6 && [type intValue] != 2 && [type intValue] != 0) { 312 | [encoded addObject:_endpoint]; 313 | } 314 | else { 315 | [encoded addObject:@""]; 316 | } 317 | 318 | if (packet.data != nil) { 319 | NSString *ackpId = @""; 320 | // This is an acknowledgement packet, so, prepend the ack pid to the data 321 | if ([type intValue] == 6) { 322 | ackpId = [NSString stringWithFormat:@":%@%@", packet.pId, @"+"]; 323 | } 324 | [encoded addObject:[NSString stringWithFormat:@"%@%@", ackpId, packet.data]]; 325 | } 326 | 327 | NSString *req = [encoded componentsJoinedByString:@":"]; 328 | if (![_transport isReady]) { 329 | DEBUGLOG(@"queue >>> %@", req); 330 | [_queue addObject:packet]; 331 | } 332 | else { 333 | DEBUGLOG(@"send() >>> %@", req); 334 | [_transport send:req]; 335 | 336 | if ([_delegate respondsToSelector:@selector(socketIO:didSendMessage:)]) { 337 | [_delegate socketIO:self didSendMessage:packet]; 338 | } 339 | } 340 | } 341 | 342 | - (void) doQueue 343 | { 344 | DEBUGLOG(@"doQueue() >> %lu", (unsigned long)[_queue count]); 345 | 346 | // TODO send all packets at once ... not as seperate packets 347 | while ([_queue count] > 0) { 348 | SocketIOPacket *packet = [_queue objectAtIndex:0]; 349 | [self send:packet]; 350 | [_queue removeObject:packet]; 351 | } 352 | } 353 | 354 | - (void) onConnect:(SocketIOPacket *)packet 355 | { 356 | DEBUGLOG(@"onConnect()"); 357 | 358 | _isConnected = YES; 359 | 360 | // Send the connected packet so the server knows what it's dealing with. 361 | // Only required when endpoint/namespace is present 362 | if ([_endpoint length] > 0) { 363 | // Make sure the packet we received has an endpoint, otherwise send it again 364 | if (![packet.endpoint isEqualToString:_endpoint]) { 365 | DEBUGLOG(@"onConnect() >> End points do not match, resending connect packet"); 366 | [self sendConnect]; 367 | return; 368 | } 369 | } 370 | 371 | _isConnecting = NO; 372 | 373 | if ([_delegate respondsToSelector:@selector(socketIODidConnect:)]) { 374 | [_delegate socketIODidConnect:self]; 375 | } 376 | 377 | // send any queued packets 378 | [self doQueue]; 379 | 380 | [self setTimeout]; 381 | } 382 | 383 | # pragma mark - 384 | # pragma mark Acknowledge methods 385 | 386 | - (NSString *) addAcknowledge:(SocketIOCallback)function 387 | { 388 | if (function) { 389 | ++_ackCount; 390 | NSString *ac = [NSString stringWithFormat:@"%ld", (long)_ackCount]; 391 | [_acks setObject:[function copy] forKey:ac]; 392 | return ac; 393 | } 394 | return nil; 395 | } 396 | 397 | - (void) removeAcknowledgeForKey:(NSString *)key 398 | { 399 | [_acks removeObjectForKey:key]; 400 | } 401 | 402 | # pragma mark - 403 | # pragma mark Heartbeat methods 404 | 405 | - (void) onTimeout 406 | { 407 | if (_timeout) { 408 | dispatch_source_cancel(_timeout); 409 | _timeout = NULL; 410 | } 411 | 412 | DEBUGLOG(@"Timed out waiting for heartbeat."); 413 | [self onDisconnect:[NSError errorWithDomain:SocketIOError 414 | code:SocketIOHeartbeatTimeout 415 | userInfo:nil]]; 416 | } 417 | 418 | - (void) setTimeout 419 | { 420 | DEBUGLOG(@"start/reset timeout"); 421 | if (_timeout) { 422 | dispatch_source_cancel(_timeout); 423 | _timeout = NULL; 424 | } 425 | 426 | _timeout = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 427 | 0, 428 | 0, 429 | dispatch_get_main_queue()); 430 | 431 | dispatch_source_set_timer(_timeout, 432 | dispatch_time(DISPATCH_TIME_NOW, _heartbeatTimeout * NSEC_PER_SEC), 433 | 0, 434 | 0); 435 | 436 | __weak SocketIO *weakSelf = self; 437 | 438 | dispatch_source_set_event_handler(_timeout, ^{ 439 | [weakSelf onTimeout]; 440 | }); 441 | 442 | dispatch_resume(_timeout); 443 | 444 | } 445 | 446 | 447 | # pragma mark - 448 | # pragma mark Regex helper method 449 | - (NSMutableArray*) getMatchesFrom:(NSString*)data with:(NSString*)regex 450 | { 451 | NSRegularExpression *nsregexTest = [NSRegularExpression regularExpressionWithPattern:regex options:0 error:nil]; 452 | NSArray *nsmatchesTest = [nsregexTest matchesInString:data options:0 range:NSMakeRange(0, [data length])]; 453 | NSMutableArray *arr = [NSMutableArray array]; 454 | 455 | for (NSTextCheckingResult *nsmatchTest in nsmatchesTest) { 456 | NSMutableArray *localMatch = [NSMutableArray array]; 457 | for (NSUInteger i = 0, l = [nsmatchTest numberOfRanges]; i < l; i++) { 458 | NSRange range = [nsmatchTest rangeAtIndex:i]; 459 | NSString *nsmatchStr = nil; 460 | if (range.location != NSNotFound && NSMaxRange(range) <= [data length]) { 461 | nsmatchStr = [data substringWithRange:[nsmatchTest rangeAtIndex:i]]; 462 | } 463 | else { 464 | nsmatchStr = @""; 465 | } 466 | [localMatch addObject:nsmatchStr]; 467 | } 468 | [arr addObject:localMatch]; 469 | } 470 | 471 | return arr; 472 | } 473 | 474 | 475 | #pragma mark - 476 | #pragma mark SocketIOTransport callbacks 477 | 478 | - (void) onData:(NSString *)data 479 | { 480 | DEBUGLOG(@"onData %@", data); 481 | 482 | // data arrived -> reset timeout 483 | [self setTimeout]; 484 | 485 | // check if data is valid (from socket.io.js) 486 | NSString *regex = @"^([^:]+):([0-9]+)?(\\+)?:([^:]+)?:?(.*)?$"; 487 | NSString *regexPieces = @"^([0-9]+)(\\+)?(.*)"; 488 | 489 | // create regex result 490 | NSMutableArray *test = [self getMatchesFrom:data with:regex]; 491 | 492 | // valid data-string arrived 493 | if ([test count] > 0) { 494 | NSArray *result = [test objectAtIndex:0]; 495 | 496 | int idx = [[result objectAtIndex:1] intValue]; 497 | SocketIOPacket *packet = [[SocketIOPacket alloc] initWithTypeIndex:idx]; 498 | 499 | packet.pId = [result objectAtIndex:2]; 500 | 501 | packet.ack = [result objectAtIndex:3]; 502 | packet.endpoint = [result objectAtIndex:4]; 503 | packet.data = [result objectAtIndex:5]; 504 | 505 | // 506 | switch (idx) { 507 | case 0: { 508 | DEBUGLOG(@"disconnect"); 509 | [self onDisconnect:[NSError errorWithDomain:SocketIOError 510 | code:SocketIOServerRespondedWithDisconnect 511 | userInfo:nil]]; 512 | break; 513 | } 514 | case 1: { 515 | DEBUGLOG(@"connected"); 516 | // from socket.io.js ... not sure when data will contain sth?! 517 | // packet.qs = data || ''; 518 | [self onConnect:packet]; 519 | break; 520 | } 521 | case 2: { 522 | DEBUGLOG(@"heartbeat"); 523 | [self sendHeartbeat]; 524 | break; 525 | } 526 | case 3: { 527 | DEBUGLOG(@"message"); 528 | if (packet.data && ![packet.data isEqualToString:@""]) { 529 | if ([_delegate respondsToSelector:@selector(socketIO:didReceiveMessage:)]) { 530 | [_delegate socketIO:self didReceiveMessage:packet]; 531 | } 532 | } 533 | break; 534 | } 535 | case 4: { 536 | DEBUGLOG(@"json"); 537 | if (packet.data && ![packet.data isEqualToString:@""]) { 538 | if ([_delegate respondsToSelector:@selector(socketIO:didReceiveJSON:)]) { 539 | [_delegate socketIO:self didReceiveJSON:packet]; 540 | } 541 | } 542 | break; 543 | } 544 | case 5: { 545 | DEBUGLOG(@"event"); 546 | if (packet.data && ![packet.data isEqualToString:@""]) { 547 | NSDictionary *json = [packet dataAsJSON]; 548 | packet.name = [json objectForKey:@"name"]; 549 | packet.args = [json objectForKey:@"args"]; 550 | if ([_delegate respondsToSelector:@selector(socketIO:didReceiveEvent:)]) { 551 | [_delegate socketIO:self didReceiveEvent:packet]; 552 | } 553 | } 554 | break; 555 | } 556 | case 6: { 557 | DEBUGLOG(@"ack"); 558 | 559 | // create regex result 560 | NSMutableArray *pieces = [self getMatchesFrom:packet.data with:regexPieces]; 561 | 562 | if ([pieces count] > 0) { 563 | NSArray *piece = [pieces objectAtIndex:0]; 564 | int ackId = [[piece objectAtIndex:1] intValue]; 565 | DEBUGLOG(@"ack id found: %d", ackId); 566 | 567 | NSString *argsStr = [piece objectAtIndex:3]; 568 | id argsData = nil; 569 | if (argsStr && ![argsStr isEqualToString:@""]) { 570 | argsData = [SocketIOJSONSerialization objectFromJSONData:[argsStr dataUsingEncoding:NSUTF8StringEncoding] error:nil]; 571 | // either send complete response or only the first arg to callback 572 | if (!_returnAllDataFromAck && [argsData count] > 0) { 573 | argsData = [argsData objectAtIndex:0]; 574 | } 575 | } 576 | 577 | // get selector for ackId 578 | NSString *key = [NSString stringWithFormat:@"%d", ackId]; 579 | SocketIOCallback callbackFunction = [_acks objectForKey:key]; 580 | if (callbackFunction != nil) { 581 | callbackFunction(argsData); 582 | [self removeAcknowledgeForKey:key]; 583 | } 584 | } 585 | 586 | break; 587 | } 588 | case 7: { 589 | DEBUGLOG(@"error"); 590 | break; 591 | } 592 | case 8: { 593 | DEBUGLOG(@"noop"); 594 | break; 595 | } 596 | default: { 597 | DEBUGLOG(@"command not found or not yet supported"); 598 | break; 599 | } 600 | } 601 | 602 | packet = nil; 603 | } 604 | else { 605 | DEBUGLOG(@"ERROR: data that has arrived wasn't valid"); 606 | } 607 | } 608 | 609 | - (void) onDisconnect:(NSError *)error 610 | { 611 | DEBUGLOG(@"onDisconnect()"); 612 | BOOL wasConnected = _isConnected; 613 | BOOL wasConnecting = _isConnecting; 614 | 615 | _isConnected = NO; 616 | _isConnecting = NO; 617 | _sid = nil; 618 | 619 | [_queue removeAllObjects]; 620 | 621 | // Kill the heartbeat timer 622 | if (_timeout) { 623 | dispatch_source_cancel(_timeout); 624 | _timeout = NULL; 625 | } 626 | 627 | // Disconnect the websocket, just in case 628 | if (_transport != nil) { 629 | // clear websocket's delegate - otherwise crashes 630 | _transport.delegate = nil; 631 | [_transport close]; 632 | } 633 | 634 | if ((wasConnected || wasConnecting)) { 635 | if ([_delegate respondsToSelector:@selector(socketIODidDisconnect:disconnectedWithError:)]) { 636 | [_delegate socketIODidDisconnect:self disconnectedWithError:error]; 637 | } 638 | } 639 | } 640 | 641 | - (void) onError:(NSError *)error 642 | { 643 | if ([_delegate respondsToSelector:@selector(socketIO:onError:)]) { 644 | [_delegate socketIO:self onError:error]; 645 | } 646 | } 647 | 648 | 649 | # pragma mark - 650 | # pragma mark Handshake callbacks (NSURLConnectionDataDelegate) 651 | - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 652 | { 653 | // check for server status code (http://gigliwood.com/weblog/Cocoa/Q__When_is_an_conne.html) 654 | if ([response respondsToSelector:@selector(statusCode)]) { 655 | NSInteger statusCode = [((NSHTTPURLResponse *)response) statusCode]; 656 | DEBUGLOG(@"didReceiveResponse() %i", statusCode); 657 | 658 | if (statusCode >= 400) { 659 | // stop connecting; no more delegate messages 660 | [connection cancel]; 661 | 662 | NSString *error = [NSString stringWithFormat:NSLocalizedString(@"Server returned status code %d", @""), statusCode]; 663 | NSDictionary *errorInfo = [NSDictionary dictionaryWithObject:error forKey:NSLocalizedDescriptionKey]; 664 | NSError *statusError = [NSError errorWithDomain:SocketIOError 665 | code:statusCode 666 | userInfo:errorInfo]; 667 | // call error callback manually 668 | [self connection:connection didFailWithError:statusError]; 669 | } 670 | } 671 | 672 | [_httpRequestData setLength:0]; 673 | } 674 | 675 | - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 676 | { 677 | [_httpRequestData appendData:data]; 678 | } 679 | 680 | - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 681 | { 682 | NSLog(@"ERROR: handshake failed ... %@", [error localizedDescription]); 683 | 684 | int errorCode = [error code] == 403 ? SocketIOUnauthorized : SocketIOHandshakeFailed; 685 | 686 | _isConnected = NO; 687 | _isConnecting = NO; 688 | 689 | if ([_delegate respondsToSelector:@selector(socketIO:onError:)]) { 690 | NSMutableDictionary *errorInfo = [[NSDictionary dictionaryWithObject:error 691 | forKey:NSUnderlyingErrorKey] mutableCopy]; 692 | 693 | NSError *err = [NSError errorWithDomain:SocketIOError 694 | code:errorCode 695 | userInfo:errorInfo]; 696 | 697 | [_delegate socketIO:self onError:err]; 698 | } 699 | } 700 | 701 | - (void) connectionDidFinishLoading:(NSURLConnection *)connection 702 | { 703 | NSString *responseString = [[NSString alloc] initWithData:_httpRequestData encoding:NSASCIIStringEncoding]; 704 | 705 | DEBUGLOG(@"connectionDidFinishLoading() %@", responseString); 706 | NSArray *data = [responseString componentsSeparatedByString:@":"]; 707 | // should be SID : heartbeat timeout : connection timeout : supported transports 708 | 709 | // check each returned value (thanks for the input https://github.com/taiyangc) 710 | BOOL connectionFailed = false; 711 | NSError* error; 712 | 713 | _sid = [data objectAtIndex:0]; 714 | if ([_sid length] < 1 || [data count] < 4) { 715 | // did not receive valid data, possibly missing a useSecure? 716 | connectionFailed = true; 717 | } 718 | else { 719 | // check SID 720 | DEBUGLOG(@"sid: %@", _sid); 721 | NSString *regex = @"[^0-9]"; 722 | NSPredicate *regexTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; 723 | if ([_sid rangeOfString:@"error"].location != NSNotFound || [regexTest evaluateWithObject:_sid]) { 724 | [self connectToHost:_host onPort:_port withParams:_params withNamespace:_endpoint]; 725 | return; 726 | } 727 | 728 | // check heartbeat timeout 729 | _heartbeatTimeout = [[data objectAtIndex:1] floatValue]; 730 | if (_heartbeatTimeout == 0.0) { 731 | // couldn't find float value -> fail 732 | connectionFailed = true; 733 | } 734 | else { 735 | // add small buffer of 7sec (magic xD) otherwise heartbeat will be too late and connection is closed 736 | _heartbeatTimeout += 7.0; 737 | } 738 | DEBUGLOG(@"heartbeatTimeout: %f", _heartbeatTimeout); 739 | 740 | // index 2 => connection timeout 741 | 742 | // get transports 743 | NSString *t = [data objectAtIndex:3]; 744 | NSArray *transports = [t componentsSeparatedByString:@","]; 745 | DEBUGLOG(@"transports: %@", transports); 746 | 747 | static Class webSocketTransportClass; 748 | static Class xhrTransportClass; 749 | 750 | if (webSocketTransportClass == nil) { 751 | webSocketTransportClass = NSClassFromString(@"SocketIOTransportWebsocket"); 752 | } 753 | if (xhrTransportClass == nil) { 754 | xhrTransportClass = NSClassFromString(@"SocketIOTransportXHR"); 755 | } 756 | 757 | if (webSocketTransportClass != nil && [transports indexOfObject:@"websocket"] != NSNotFound) { 758 | DEBUGLOG(@"websocket supported -> using it now"); 759 | _transport = [[webSocketTransportClass alloc] initWithDelegate:self]; 760 | } 761 | else if (xhrTransportClass != nil && [transports indexOfObject:@"xhr-polling"] != NSNotFound) { 762 | DEBUGLOG(@"xhr polling supported -> using it now"); 763 | _transport = [[xhrTransportClass alloc] initWithDelegate:self]; 764 | } 765 | else { 766 | DEBUGLOG(@"no transport found that is supported :( -> fail"); 767 | connectionFailed = true; 768 | error = [NSError errorWithDomain:SocketIOError 769 | code:SocketIOTransportsNotSupported 770 | userInfo:nil]; 771 | } 772 | } 773 | 774 | // if connection didn't return the values we need -> fail 775 | if (connectionFailed) { 776 | // error already set!? 777 | if (error == nil) { 778 | error = [NSError errorWithDomain:SocketIOError 779 | code:SocketIOServerRespondedWithInvalidConnectionData 780 | userInfo:nil]; 781 | } 782 | 783 | if ([_delegate respondsToSelector:@selector(socketIO:onError:)]) { 784 | [_delegate socketIO:self onError:error]; 785 | } 786 | 787 | // make sure to do call all cleanup code 788 | [self onDisconnect:error]; 789 | 790 | return; 791 | } 792 | 793 | [_transport open]; 794 | } 795 | 796 | #if DEBUG_CERTIFICATE 797 | 798 | // to deal with self-signed certificates 799 | - (BOOL) connection:(NSURLConnection *)connection 800 | canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace 801 | { 802 | return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; 803 | } 804 | 805 | - (void) connection:(NSURLConnection *)connection 806 | didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 807 | { 808 | if ([challenge.protectionSpace.authenticationMethod 809 | isEqualToString:NSURLAuthenticationMethodServerTrust]) { 810 | // we only trust our own domain 811 | if ([challenge.protectionSpace.host isEqualToString:_host]) { 812 | SecTrustRef trust = challenge.protectionSpace.serverTrust; 813 | NSURLCredential *credential = [NSURLCredential credentialForTrust:trust]; 814 | [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; 815 | } 816 | } 817 | 818 | [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; 819 | } 820 | #endif 821 | 822 | 823 | # pragma mark - 824 | 825 | - (void) dealloc 826 | { 827 | [_handshake cancel]; 828 | _handshake = nil; 829 | 830 | _host = nil; 831 | _sid = nil; 832 | _endpoint = nil; 833 | 834 | _transport.delegate = nil; 835 | _transport = nil; 836 | 837 | if (_timeout) { 838 | dispatch_source_cancel(_timeout); 839 | _timeout = NULL; 840 | } 841 | 842 | _queue = nil; 843 | _acks = nil; 844 | } 845 | 846 | 847 | @end 848 | -------------------------------------------------------------------------------- /SocketIOJSONSerialization.h: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOJSONSerialization.h 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import 22 | 23 | @interface SocketIOJSONSerialization : NSObject 24 | 25 | + (id) objectFromJSONData:(NSData *)data error:(NSError **)error; 26 | + (NSString *) JSONStringFromObject:(id)object error:(NSError **)error; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /SocketIOJSONSerialization.m: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOJSONSerialization.m 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import "SocketIOJSONSerialization.h" 22 | 23 | @implementation SocketIOJSONSerialization 24 | 25 | + (id) objectFromJSONData:(NSData *)data error:(NSError **)error { 26 | return [NSJSONSerialization JSONObjectWithData:data options:0 error:error]; 27 | } 28 | 29 | + (NSString *) JSONStringFromObject:(id)object error:(NSError **)error { 30 | NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:error]; 31 | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /SocketIOPacket.h: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOPacket.h 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import 22 | 23 | @interface SocketIOPacket : NSObject 24 | { 25 | NSString *type; 26 | NSString *pId; 27 | NSString *ack; 28 | NSString *name; 29 | NSString *data; 30 | NSArray *args; 31 | NSString *endpoint; 32 | NSArray *_types; 33 | } 34 | 35 | @property (nonatomic, copy) NSString *type; 36 | @property (nonatomic, copy) NSString *pId; 37 | @property (nonatomic, copy) NSString *ack; 38 | @property (nonatomic, copy) NSString *name; 39 | @property (nonatomic, copy) NSString *data; 40 | @property (nonatomic, copy) NSString *endpoint; 41 | @property (nonatomic, copy) NSArray *args; 42 | 43 | - (id) initWithType:(NSString *)packetType; 44 | - (id) initWithTypeIndex:(int)index; 45 | - (id) dataAsJSON; 46 | - (NSNumber *) typeAsNumber; 47 | - (NSString *) typeForIndex:(int)index; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /SocketIOPacket.m: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOPacket.h 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import "SocketIOPacket.h" 22 | #import "SocketIOJSONSerialization.h" 23 | 24 | @implementation SocketIOPacket 25 | 26 | @synthesize type, pId, name, ack, data, args, endpoint; 27 | 28 | - (id) init 29 | { 30 | self = [super init]; 31 | if (self) { 32 | _types = [NSArray arrayWithObjects: @"disconnect", 33 | @"connect", 34 | @"heartbeat", 35 | @"message", 36 | @"json", 37 | @"event", 38 | @"ack", 39 | @"error", 40 | @"noop", 41 | nil]; 42 | } 43 | return self; 44 | } 45 | 46 | - (id) initWithType:(NSString *)packetType 47 | { 48 | self = [self init]; 49 | if (self) { 50 | self.type = packetType; 51 | } 52 | return self; 53 | } 54 | 55 | - (id) initWithTypeIndex:(int)index 56 | { 57 | self = [self init]; 58 | if (self) { 59 | self.type = [self typeForIndex:index]; 60 | } 61 | return self; 62 | } 63 | 64 | - (id) dataAsJSON 65 | { 66 | if (self.data) { 67 | NSData *utf8Data = [self.data dataUsingEncoding:NSUTF8StringEncoding]; 68 | return [SocketIOJSONSerialization objectFromJSONData:utf8Data error:nil]; 69 | } 70 | else { 71 | return nil; 72 | } 73 | } 74 | 75 | - (NSNumber *) typeAsNumber 76 | { 77 | NSUInteger index = [_types indexOfObject:self.type]; 78 | NSNumber *num = [NSNumber numberWithUnsignedInteger:index]; 79 | return num; 80 | } 81 | 82 | - (NSString *) typeForIndex:(int)index 83 | { 84 | return [_types objectAtIndex:index]; 85 | } 86 | 87 | - (void) dealloc 88 | { 89 | _types = nil; 90 | 91 | type = nil; 92 | pId = nil; 93 | name = nil; 94 | ack = nil; 95 | data = nil; 96 | args = nil; 97 | endpoint = nil; 98 | } 99 | 100 | @end 101 | 102 | -------------------------------------------------------------------------------- /SocketIOTransport.h: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOTransport.h 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import 22 | 23 | @protocol SocketIOTransportDelegate 24 | 25 | - (void) onData:(id)message; 26 | - (void) onDisconnect:(NSError*)error; 27 | - (void) onError:(NSError*)error; 28 | 29 | @property (nonatomic, readonly) NSString *host; 30 | @property (nonatomic, readonly) NSInteger port; 31 | @property (nonatomic, readonly) NSString *sid; 32 | @property (nonatomic, readonly) NSTimeInterval heartbeatTimeout; 33 | @property (nonatomic) BOOL useSecure; 34 | 35 | @end 36 | 37 | @protocol SocketIOTransport 38 | 39 | - (id) initWithDelegate:(id )delegate; 40 | - (void) open; 41 | - (void) close; 42 | - (BOOL) isReady; 43 | - (void) send:(NSString *)request; 44 | 45 | @property (nonatomic, weak) id delegate; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /SocketIOTransportWebsocket.h: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOTransportWebsocket.h 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import 22 | 23 | #import "SRWebSocket.h" 24 | #import "SocketIOTransport.h" 25 | 26 | @interface SocketIOTransportWebsocket : NSObject 27 | { 28 | SRWebSocket *_webSocket; 29 | } 30 | 31 | @property (nonatomic, weak) id delegate; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /SocketIOTransportWebsocket.m: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOTransportWebsocket.m 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import "SocketIOTransportWebsocket.h" 22 | #import "SocketIO.h" 23 | 24 | #define DEBUG_LOGS 0 25 | 26 | #if DEBUG_LOGS 27 | #define DEBUGLOG(...) NSLog(__VA_ARGS__) 28 | #else 29 | #define DEBUGLOG(...) 30 | #endif 31 | 32 | static NSString* kInsecureSocketURL = @"ws://%@/socket.io/1/websocket/%@"; 33 | static NSString* kSecureSocketURL = @"wss://%@/socket.io/1/websocket/%@"; 34 | static NSString* kInsecureSocketPortURL = @"ws://%@:%d/socket.io/1/websocket/%@"; 35 | static NSString* kSecureSocketPortURL = @"wss://%@:%d/socket.io/1/websocket/%@"; 36 | 37 | @implementation SocketIOTransportWebsocket 38 | 39 | @synthesize delegate; 40 | 41 | - (id) initWithDelegate:(id)delegate_ 42 | { 43 | self = [super init]; 44 | if (self) { 45 | self.delegate = delegate_; 46 | } 47 | return self; 48 | } 49 | 50 | - (BOOL) isReady 51 | { 52 | return _webSocket.readyState == SR_OPEN; 53 | } 54 | 55 | - (void) open 56 | { 57 | NSString *urlStr; 58 | NSString *format; 59 | if (delegate.port) { 60 | format = delegate.useSecure ? kSecureSocketPortURL : kInsecureSocketPortURL; 61 | urlStr = [NSString stringWithFormat:format, delegate.host, delegate.port, delegate.sid]; 62 | } 63 | else { 64 | format = delegate.useSecure ? kSecureSocketURL : kInsecureSocketURL; 65 | urlStr = [NSString stringWithFormat:format, delegate.host, delegate.sid]; 66 | } 67 | NSURL *url = [NSURL URLWithString:urlStr]; 68 | 69 | _webSocket = nil; 70 | 71 | _webSocket = [[SRWebSocket alloc] initWithURL:url]; 72 | _webSocket.delegate = self; 73 | DEBUGLOG(@"Opening %@", url); 74 | [_webSocket open]; 75 | } 76 | 77 | - (void) dealloc 78 | { 79 | [_webSocket setDelegate:nil]; 80 | } 81 | 82 | - (void) close 83 | { 84 | [_webSocket close]; 85 | } 86 | 87 | - (void) send:(NSString*)request 88 | { 89 | [_webSocket send:request]; 90 | } 91 | 92 | 93 | 94 | # pragma mark - 95 | # pragma mark WebSocket Delegate Methods 96 | 97 | - (void) webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message 98 | { 99 | if([delegate respondsToSelector:@selector(onData:)]) { 100 | [delegate onData:message]; 101 | } 102 | } 103 | 104 | - (void) webSocketDidOpen:(SRWebSocket *)webSocket 105 | { 106 | DEBUGLOG(@"Socket opened."); 107 | } 108 | 109 | - (void) webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error 110 | { 111 | DEBUGLOG(@"Socket failed with error ... %@", [error localizedDescription]); 112 | // Assuming this resulted in a disconnect 113 | if([delegate respondsToSelector:@selector(onDisconnect:)]) { 114 | [delegate onDisconnect:error]; 115 | } 116 | } 117 | 118 | - (void) webSocket:(SRWebSocket *)webSocket 119 | didCloseWithCode:(NSInteger)code 120 | reason:(NSString *)reason 121 | wasClean:(BOOL)wasClean 122 | { 123 | DEBUGLOG(@"Socket closed. %@", reason); 124 | if([delegate respondsToSelector:@selector(onDisconnect:)]) { 125 | [delegate onDisconnect:[NSError errorWithDomain:SocketIOError 126 | code:SocketIOWebSocketClosed 127 | userInfo:nil]]; 128 | } 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /SocketIOTransportXHR.h: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOTransportXHR.h 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import 22 | 23 | #import "SocketIOTransport.h" 24 | 25 | @interface SocketIOTransportXHR : NSObject 26 | { 27 | NSString *_url; 28 | NSMutableData *_data; 29 | NSMutableDictionary *_polls; 30 | BOOL _isClosed; 31 | } 32 | 33 | @property (nonatomic, weak) id delegate; 34 | @property (nonatomic) BOOL isClosed; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /SocketIOTransportXHR.m: -------------------------------------------------------------------------------- 1 | // 2 | // SocketIOTransportXHR.m 3 | // v0.5.1 4 | // 5 | // based on 6 | // socketio-cocoa https://github.com/fpotter/socketio-cocoa 7 | // by Fred Potter 8 | // 9 | // using 10 | // https://github.com/square/SocketRocket 11 | // 12 | // reusing some parts of 13 | // /socket.io/socket.io.js 14 | // 15 | // Created by Philipp Kyeck http://beta-interactive.de 16 | // 17 | // With help from 18 | // https://github.com/pkyeck/socket.IO-objc/blob/master/CONTRIBUTORS.md 19 | // 20 | 21 | #import "SocketIOTransportXHR.h" 22 | #import "SocketIO.h" 23 | 24 | #define DEBUG_LOGS 0 25 | 26 | #if DEBUG_LOGS 27 | #define DEBUGLOG(...) NSLog(__VA_ARGS__) 28 | #else 29 | #define DEBUGLOG(...) 30 | #endif 31 | 32 | static NSString* kInsecureXHRURL = @"http://%@/socket.io/1/xhr-polling/%@"; 33 | static NSString* kSecureXHRURL = @"https://%@/socket.io/1/xhr-polling/%@"; 34 | static NSString* kInsecureXHRPortURL = @"http://%@:%d/socket.io/1/xhr-polling/%@"; 35 | static NSString* kSecureXHRPortURL = @"https://%@:%d/socket.io/1/xhr-polling/%@"; 36 | 37 | @interface SocketIOTransportXHR (Private) 38 | - (void) checkAndStartPoll; 39 | - (void) poll:(NSString *)data; 40 | - (void) poll:(NSString *)data retryNumber:(int)retry; 41 | @end 42 | 43 | @implementation SocketIOTransportXHR 44 | 45 | @synthesize delegate, 46 | isClosed = _isClosed; 47 | 48 | - (id) initWithDelegate:(id)delegate_ 49 | { 50 | self = [super init]; 51 | if (self) { 52 | self.delegate = delegate_; 53 | _data = [[NSMutableData alloc] init]; 54 | _polls = [[NSMutableDictionary alloc] init]; 55 | } 56 | return self; 57 | } 58 | 59 | - (void) open 60 | { 61 | NSString *format; 62 | if (delegate.port) { 63 | format = delegate.useSecure ? kSecureXHRPortURL : kInsecureXHRPortURL; 64 | _url = [NSString stringWithFormat:format, delegate.host, delegate.port, delegate.sid]; 65 | } 66 | else { 67 | format = delegate.useSecure ? kSecureXHRURL : kInsecureXHRURL; 68 | _url = [NSString stringWithFormat:format, delegate.host, delegate.sid]; 69 | } 70 | DEBUGLOG(@"Opening XHR @ %@", _url); 71 | [self poll:nil]; 72 | } 73 | 74 | - (void) close 75 | { 76 | NSMutableDictionary *pollData; 77 | NSURLConnection *conn; 78 | for (NSString *key in _polls) { 79 | pollData = [_polls objectForKey:key]; 80 | conn = [pollData objectForKey:@"connection"]; 81 | [conn cancel]; 82 | } 83 | [_polls removeAllObjects]; 84 | 85 | _isClosed = YES; 86 | } 87 | 88 | - (BOOL) isReady 89 | { 90 | return YES; 91 | } 92 | 93 | - (void) send:(NSString *)request 94 | { 95 | [self poll:request]; 96 | } 97 | 98 | 99 | #pragma mark - 100 | #pragma mark private methods 101 | 102 | - (void) checkAndStartPoll 103 | { 104 | if (_isClosed) { 105 | return; 106 | } 107 | 108 | BOOL restart = NO; 109 | // no polls currently running -> start one 110 | if ([_polls count] == 0) { 111 | restart = YES; 112 | } 113 | else { 114 | restart = YES; 115 | // look for polls w/o data -> if there, no need to restart 116 | for (NSString *key in _polls) { 117 | NSMutableDictionary *pollData = [_polls objectForKey:key]; 118 | if ([pollData objectForKey:@"data"] == nil) { 119 | restart = NO; 120 | break; 121 | } 122 | } 123 | } 124 | 125 | if (restart) { 126 | [self poll:nil]; 127 | } 128 | } 129 | 130 | - (void) poll:(NSString *)data 131 | { 132 | [self poll:data retryNumber:0]; 133 | } 134 | 135 | - (void) poll:(NSString *)data retryNumber:(int)retry 136 | { 137 | NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970]; 138 | double unix = timeStamp * 1000; 139 | NSString *url = [_url stringByAppendingString:[NSString stringWithFormat:@"?t=%.0f", unix]]; 140 | 141 | DEBUGLOG(@"---------------------------------------------------------------------------------------"); 142 | DEBUGLOG(@"poll() %@", url); 143 | 144 | NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] 145 | cachePolicy:NSURLRequestUseProtocolCachePolicy 146 | timeoutInterval:[delegate heartbeatTimeout]]; 147 | if (data != nil) { 148 | DEBUGLOG(@"poll() %@", data); 149 | [req setHTTPMethod:@"POST"]; 150 | [req setValue:@"text/plain; charset=UTF-8" forHTTPHeaderField:@"Content-Type"]; 151 | [req setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]]; 152 | } 153 | [req setValue:@"Keep-Alive" forHTTPHeaderField:@"Connection"]; 154 | 155 | NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self]; 156 | 157 | // add pollData to polls dictionary 158 | NSMutableDictionary *pollData = [[NSMutableDictionary alloc] init]; 159 | [pollData setObject:[NSNumber numberWithInt:retry] forKey:@"retries"]; 160 | [pollData setObject:conn forKey:@"connection"]; 161 | [pollData setValue:data forKey:@"data"]; 162 | [_polls setObject:pollData forKey:conn.description]; 163 | 164 | [conn start]; 165 | } 166 | 167 | 168 | #pragma mark - 169 | #pragma mark NSURLConnection delegate methods 170 | 171 | 172 | - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 173 | { 174 | // check for server status code (http://gigliwood.com/weblog/Cocoa/Q__When_is_an_conne.html) 175 | if ([response respondsToSelector:@selector(statusCode)]) { 176 | NSInteger statusCode = [((NSHTTPURLResponse *)response) statusCode]; 177 | DEBUGLOG(@"didReceiveResponse() %i", statusCode); 178 | 179 | if (statusCode >= 400) { 180 | // stop connecting; no more delegate messages 181 | [connection cancel]; 182 | 183 | NSString *error = [NSString stringWithFormat:NSLocalizedString(@"Server returned status code %d", @""), statusCode]; 184 | NSDictionary *errorInfo = [NSDictionary dictionaryWithObject:error forKey:NSLocalizedDescriptionKey]; 185 | NSError *statusError = [NSError errorWithDomain:SocketIOError 186 | code:statusCode 187 | userInfo:errorInfo]; 188 | 189 | if ([delegate respondsToSelector:@selector(onError:)]) { 190 | [delegate onError:statusError]; 191 | } 192 | } 193 | } 194 | 195 | [_data setLength:0]; 196 | } 197 | 198 | - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 199 | { 200 | DEBUGLOG(@"didReceiveData(): %@", data); 201 | [_data appendData:data]; 202 | } 203 | 204 | - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 205 | { 206 | DEBUGLOG(@"didFailWithError: %@", [error localizedDescription]); 207 | 208 | // retry 3 times or throw error 209 | NSMutableDictionary *pollData = [_polls objectForKey:connection.description]; 210 | NSString *data = [pollData objectForKey:@"data"]; 211 | [_polls removeObjectForKey:connection.description]; 212 | 213 | NSNumber *retries = [pollData objectForKey:@"retries"]; 214 | if ([retries intValue] < 2) { 215 | [self poll:data retryNumber:[retries intValue] + 1]; 216 | } 217 | else { 218 | NSMutableDictionary *errorInfo = [[NSMutableDictionary alloc] init]; 219 | [errorInfo setValue:[error localizedDescription] forKey:@"reason"]; 220 | [errorInfo setValue:data forKey:@"data"]; 221 | 222 | if ([delegate respondsToSelector:@selector(onError:)]) { 223 | [delegate onError:[NSError errorWithDomain:SocketIOError 224 | code:SocketIODataCouldNotBeSend 225 | userInfo:errorInfo]]; 226 | } 227 | } 228 | } 229 | 230 | // Sometimes Socket.IO "batches" up messages in one packet, so we have to split them. 231 | - (NSArray *)packetsFromPayload:(NSString *)payload 232 | { 233 | // "Batched" format is: 234 | // �[packet_0 length]�[packet_0]�[packet_1 length]�[packet_1]�[packet_n length]�[packet_n] 235 | 236 | if ([payload hasPrefix:@"\ufffd"]) { 237 | // Payload has multiple packets, split based on the '�' character 238 | // Skip the first character, then split 239 | NSArray *split = [[payload substringFromIndex:1] componentsSeparatedByString:@"\ufffd"]; 240 | 241 | // Init array with [split count] / 2 because we only need the odd-numbered 242 | NSMutableArray *packets = [NSMutableArray arrayWithCapacity:[split count]/2]; 243 | 244 | // Now all of the odd-numbered indices are the packets (1, 3, 5, etc.) 245 | [split enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 246 | if (idx % 2 != 0) { 247 | [packets addObject:obj]; 248 | } 249 | }]; 250 | 251 | NSLog(@"Parsed a payload!"); 252 | return packets; 253 | } 254 | else { 255 | // Regular single-packet payload 256 | return @[payload]; 257 | } 258 | } 259 | 260 | - (void) connectionDidFinishLoading:(NSURLConnection *)connection 261 | { 262 | NSString *message = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding]; 263 | DEBUGLOG(@"response: __%@__", message); 264 | 265 | if (![message isEqualToString:@"1"]) { 266 | NSArray *messages = [self packetsFromPayload:message]; 267 | if([delegate respondsToSelector:@selector(onData:)]) { 268 | [messages enumerateObjectsUsingBlock:^(NSString *message, NSUInteger idx, BOOL *stop) { 269 | [delegate onData:message]; 270 | }]; 271 | } 272 | } 273 | 274 | // remove current connection from pool 275 | [_polls removeObjectForKey:connection.description]; 276 | 277 | [self checkAndStartPoll]; 278 | } 279 | 280 | 281 | @end 282 | -------------------------------------------------------------------------------- /SocketTesterARC.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4A444FA11589E28800B44ABB /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A444FA01589E28800B44ABB /* libicucore.dylib */; }; 11 | 4A444FA31589E29500B44ABB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A444FA21589E29500B44ABB /* Security.framework */; }; 12 | 4A4453811589EE9100B44ABB /* base64.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A44537A1589EE9100B44ABB /* base64.c */; }; 13 | 4A4453821589EE9100B44ABB /* NSData+SRB64Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A44537D1589EE9100B44ABB /* NSData+SRB64Additions.m */; }; 14 | 4A4453831589EE9100B44ABB /* SRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A4453801589EE9100B44ABB /* SRWebSocket.m */; }; 15 | 4AD96DF41680853E00D9E42D /* SocketIOPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AD96DF31680853E00D9E42D /* SocketIOPacket.m */; }; 16 | 4AD96DF816808B7900D9E42D /* SocketIOTransportWebsocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AD96DF716808B7900D9E42D /* SocketIOTransportWebsocket.m */; }; 17 | 4AD96DFC16822DE300D9E42D /* SocketIOTransportXHR.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AD96DFB16822DE300D9E42D /* SocketIOTransportXHR.m */; }; 18 | 4ADCCBA215790D760022990C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ADCCBA115790D760022990C /* UIKit.framework */; }; 19 | 4ADCCBA415790D760022990C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ADCCBA315790D760022990C /* Foundation.framework */; }; 20 | 4ADCCBA615790D760022990C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ADCCBA515790D760022990C /* CoreGraphics.framework */; }; 21 | 4ADCCBAC15790D760022990C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4ADCCBAA15790D760022990C /* InfoPlist.strings */; }; 22 | 4ADCCBAE15790D760022990C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ADCCBAD15790D760022990C /* main.m */; }; 23 | 4ADCCBB215790D760022990C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ADCCBB115790D760022990C /* AppDelegate.m */; }; 24 | 4ADCCBB515790D760022990C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ADCCBB415790D760022990C /* ViewController.m */; }; 25 | 4ADCCBB815790D760022990C /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4ADCCBB615790D760022990C /* ViewController.xib */; }; 26 | 4ADCCBEF15790FC70022990C /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ADCCBEE15790FC70022990C /* CFNetwork.framework */; }; 27 | 4ADCCBF115790FD30022990C /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ADCCBF015790FD30022990C /* MobileCoreServices.framework */; }; 28 | 4ADCCBF315790FDF0022990C /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ADCCBF215790FDF0022990C /* SystemConfiguration.framework */; }; 29 | 4ADCCD4D157915F00022990C /* SocketIO.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ADCCBC715790DEC0022990C /* SocketIO.m */; }; 30 | C9E391A215E2A1B00004693A /* SocketIOJSONSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = C9E391A115E2A1B00004693A /* SocketIOJSONSerialization.m */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 4A444FA01589E28800B44ABB /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; }; 35 | 4A444FA21589E29500B44ABB /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 36 | 4A44537A1589EE9100B44ABB /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = base64.c; path = "submodules/socket-rocket/SocketRocket/base64.c"; sourceTree = SOURCE_ROOT; }; 37 | 4A44537B1589EE9100B44ABB /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = base64.h; path = "submodules/socket-rocket/SocketRocket/base64.h"; sourceTree = SOURCE_ROOT; }; 38 | 4A44537C1589EE9100B44ABB /* NSData+SRB64Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSData+SRB64Additions.h"; path = "submodules/socket-rocket/SocketRocket/NSData+SRB64Additions.h"; sourceTree = SOURCE_ROOT; }; 39 | 4A44537D1589EE9100B44ABB /* NSData+SRB64Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSData+SRB64Additions.m"; path = "submodules/socket-rocket/SocketRocket/NSData+SRB64Additions.m"; sourceTree = SOURCE_ROOT; }; 40 | 4A44537E1589EE9100B44ABB /* SocketRocket-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SocketRocket-Prefix.pch"; path = "submodules/socket-rocket/SocketRocket/SocketRocket-Prefix.pch"; sourceTree = SOURCE_ROOT; }; 41 | 4A44537F1589EE9100B44ABB /* SRWebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SRWebSocket.h; path = "submodules/socket-rocket/SocketRocket/SRWebSocket.h"; sourceTree = SOURCE_ROOT; }; 42 | 4A4453801589EE9100B44ABB /* SRWebSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SRWebSocket.m; path = "submodules/socket-rocket/SocketRocket/SRWebSocket.m"; sourceTree = SOURCE_ROOT; }; 43 | 4AD96DF21680853E00D9E42D /* SocketIOPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SocketIOPacket.h; sourceTree = SOURCE_ROOT; }; 44 | 4AD96DF31680853E00D9E42D /* SocketIOPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SocketIOPacket.m; sourceTree = SOURCE_ROOT; }; 45 | 4AD96DF616808B7900D9E42D /* SocketIOTransportWebsocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SocketIOTransportWebsocket.h; path = ../SocketIOTransportWebsocket.h; sourceTree = ""; }; 46 | 4AD96DF716808B7900D9E42D /* SocketIOTransportWebsocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SocketIOTransportWebsocket.m; path = ../SocketIOTransportWebsocket.m; sourceTree = ""; }; 47 | 4AD96DF9168225FC00D9E42D /* SocketIOTransport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SocketIOTransport.h; sourceTree = SOURCE_ROOT; }; 48 | 4AD96DFA16822DE300D9E42D /* SocketIOTransportXHR.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SocketIOTransportXHR.h; sourceTree = SOURCE_ROOT; }; 49 | 4AD96DFB16822DE300D9E42D /* SocketIOTransportXHR.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SocketIOTransportXHR.m; sourceTree = SOURCE_ROOT; }; 50 | 4ADCCB9D15790D760022990C /* SocketTesterARC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SocketTesterARC.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 4ADCCBA115790D760022990C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 52 | 4ADCCBA315790D760022990C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 53 | 4ADCCBA515790D760022990C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 54 | 4ADCCBA915790D760022990C /* SocketTesterARC-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SocketTesterARC-Info.plist"; sourceTree = ""; }; 55 | 4ADCCBAB15790D760022990C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 56 | 4ADCCBAD15790D760022990C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 57 | 4ADCCBAF15790D760022990C /* SocketTesterARC-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SocketTesterARC-Prefix.pch"; sourceTree = ""; }; 58 | 4ADCCBB015790D760022990C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 59 | 4ADCCBB115790D760022990C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 60 | 4ADCCBB315790D760022990C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 61 | 4ADCCBB415790D760022990C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 62 | 4ADCCBB715790D760022990C /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ViewController.xib; sourceTree = ""; }; 63 | 4ADCCBC615790DEC0022990C /* SocketIO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SocketIO.h; path = ../SocketIO.h; sourceTree = ""; }; 64 | 4ADCCBC715790DEC0022990C /* SocketIO.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SocketIO.m; path = ../SocketIO.m; sourceTree = ""; }; 65 | 4ADCCBEE15790FC70022990C /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 66 | 4ADCCBF015790FD30022990C /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 67 | 4ADCCBF215790FDF0022990C /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 68 | C9E391A015E2A1B00004693A /* SocketIOJSONSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SocketIOJSONSerialization.h; sourceTree = SOURCE_ROOT; }; 69 | C9E391A115E2A1B00004693A /* SocketIOJSONSerialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SocketIOJSONSerialization.m; sourceTree = SOURCE_ROOT; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | 4ADCCB9A15790D760022990C /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | 4A444FA31589E29500B44ABB /* Security.framework in Frameworks */, 78 | 4A444FA11589E28800B44ABB /* libicucore.dylib in Frameworks */, 79 | 4ADCCBEF15790FC70022990C /* CFNetwork.framework in Frameworks */, 80 | 4ADCCBA615790D760022990C /* CoreGraphics.framework in Frameworks */, 81 | 4ADCCBA415790D760022990C /* Foundation.framework in Frameworks */, 82 | 4ADCCBF115790FD30022990C /* MobileCoreServices.framework in Frameworks */, 83 | 4ADCCBF315790FDF0022990C /* SystemConfiguration.framework in Frameworks */, 84 | 4ADCCBA215790D760022990C /* UIKit.framework in Frameworks */, 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | /* End PBXFrameworksBuildPhase section */ 89 | 90 | /* Begin PBXGroup section */ 91 | 4A4453791589EE7D00B44ABB /* SocketRocket */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 4A44537A1589EE9100B44ABB /* base64.c */, 95 | 4A44537B1589EE9100B44ABB /* base64.h */, 96 | 4A44537C1589EE9100B44ABB /* NSData+SRB64Additions.h */, 97 | 4A44537D1589EE9100B44ABB /* NSData+SRB64Additions.m */, 98 | 4A44537E1589EE9100B44ABB /* SocketRocket-Prefix.pch */, 99 | 4A44537F1589EE9100B44ABB /* SRWebSocket.h */, 100 | 4A4453801589EE9100B44ABB /* SRWebSocket.m */, 101 | ); 102 | name = SocketRocket; 103 | sourceTree = ""; 104 | }; 105 | 4ADCCB9215790D760022990C = { 106 | isa = PBXGroup; 107 | children = ( 108 | 4ADCCBA715790D760022990C /* SocketTesterARC */, 109 | 4ADCCBA015790D760022990C /* Frameworks */, 110 | 4ADCCB9E15790D760022990C /* Products */, 111 | ); 112 | sourceTree = ""; 113 | }; 114 | 4ADCCB9E15790D760022990C /* Products */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 4ADCCB9D15790D760022990C /* SocketTesterARC.app */, 118 | ); 119 | name = Products; 120 | sourceTree = ""; 121 | }; 122 | 4ADCCBA015790D760022990C /* Frameworks */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 4A444FA21589E29500B44ABB /* Security.framework */, 126 | 4A444FA01589E28800B44ABB /* libicucore.dylib */, 127 | 4ADCCBF215790FDF0022990C /* SystemConfiguration.framework */, 128 | 4ADCCBF015790FD30022990C /* MobileCoreServices.framework */, 129 | 4ADCCBEE15790FC70022990C /* CFNetwork.framework */, 130 | 4ADCCBA115790D760022990C /* UIKit.framework */, 131 | 4ADCCBA315790D760022990C /* Foundation.framework */, 132 | 4ADCCBA515790D760022990C /* CoreGraphics.framework */, 133 | ); 134 | name = Frameworks; 135 | sourceTree = ""; 136 | }; 137 | 4ADCCBA715790D760022990C /* SocketTesterARC */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 4A4453791589EE7D00B44ABB /* SocketRocket */, 141 | 4ADCCBB015790D760022990C /* AppDelegate.h */, 142 | 4ADCCBB115790D760022990C /* AppDelegate.m */, 143 | 4ADCCBB315790D760022990C /* ViewController.h */, 144 | 4ADCCBB415790D760022990C /* ViewController.m */, 145 | 4ADCCBB615790D760022990C /* ViewController.xib */, 146 | 4ADCCBC615790DEC0022990C /* SocketIO.h */, 147 | 4ADCCBC715790DEC0022990C /* SocketIO.m */, 148 | 4AD96DF21680853E00D9E42D /* SocketIOPacket.h */, 149 | 4AD96DF31680853E00D9E42D /* SocketIOPacket.m */, 150 | C9E391A015E2A1B00004693A /* SocketIOJSONSerialization.h */, 151 | C9E391A115E2A1B00004693A /* SocketIOJSONSerialization.m */, 152 | 4AD96DF9168225FC00D9E42D /* SocketIOTransport.h */, 153 | 4AD96DF616808B7900D9E42D /* SocketIOTransportWebsocket.h */, 154 | 4AD96DF716808B7900D9E42D /* SocketIOTransportWebsocket.m */, 155 | 4AD96DFA16822DE300D9E42D /* SocketIOTransportXHR.h */, 156 | 4AD96DFB16822DE300D9E42D /* SocketIOTransportXHR.m */, 157 | 4ADCCBA815790D760022990C /* Supporting Files */, 158 | ); 159 | path = SocketTesterARC; 160 | sourceTree = ""; 161 | }; 162 | 4ADCCBA815790D760022990C /* Supporting Files */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 4ADCCBA915790D760022990C /* SocketTesterARC-Info.plist */, 166 | 4ADCCBAA15790D760022990C /* InfoPlist.strings */, 167 | 4ADCCBAD15790D760022990C /* main.m */, 168 | 4ADCCBAF15790D760022990C /* SocketTesterARC-Prefix.pch */, 169 | ); 170 | name = "Supporting Files"; 171 | sourceTree = ""; 172 | }; 173 | /* End PBXGroup section */ 174 | 175 | /* Begin PBXNativeTarget section */ 176 | 4ADCCB9C15790D760022990C /* SocketTesterARC */ = { 177 | isa = PBXNativeTarget; 178 | buildConfigurationList = 4ADCCBBB15790D760022990C /* Build configuration list for PBXNativeTarget "SocketTesterARC" */; 179 | buildPhases = ( 180 | 4ADCCB9915790D760022990C /* Sources */, 181 | 4ADCCB9A15790D760022990C /* Frameworks */, 182 | 4ADCCB9B15790D760022990C /* Resources */, 183 | ); 184 | buildRules = ( 185 | ); 186 | dependencies = ( 187 | ); 188 | name = SocketTesterARC; 189 | productName = SocketTesterARC; 190 | productReference = 4ADCCB9D15790D760022990C /* SocketTesterARC.app */; 191 | productType = "com.apple.product-type.application"; 192 | }; 193 | /* End PBXNativeTarget section */ 194 | 195 | /* Begin PBXProject section */ 196 | 4ADCCB9415790D760022990C /* Project object */ = { 197 | isa = PBXProject; 198 | attributes = { 199 | LastUpgradeCheck = 0460; 200 | ORGANIZATIONNAME = beta_interactive; 201 | }; 202 | buildConfigurationList = 4ADCCB9715790D760022990C /* Build configuration list for PBXProject "SocketTesterARC" */; 203 | compatibilityVersion = "Xcode 3.2"; 204 | developmentRegion = English; 205 | hasScannedForEncodings = 0; 206 | knownRegions = ( 207 | en, 208 | ); 209 | mainGroup = 4ADCCB9215790D760022990C; 210 | productRefGroup = 4ADCCB9E15790D760022990C /* Products */; 211 | projectDirPath = ""; 212 | projectRoot = ""; 213 | targets = ( 214 | 4ADCCB9C15790D760022990C /* SocketTesterARC */, 215 | ); 216 | }; 217 | /* End PBXProject section */ 218 | 219 | /* Begin PBXResourcesBuildPhase section */ 220 | 4ADCCB9B15790D760022990C /* Resources */ = { 221 | isa = PBXResourcesBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | 4ADCCBAC15790D760022990C /* InfoPlist.strings in Resources */, 225 | 4ADCCBB815790D760022990C /* ViewController.xib in Resources */, 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | /* End PBXResourcesBuildPhase section */ 230 | 231 | /* Begin PBXSourcesBuildPhase section */ 232 | 4ADCCB9915790D760022990C /* Sources */ = { 233 | isa = PBXSourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | 4ADCCD4D157915F00022990C /* SocketIO.m in Sources */, 237 | 4ADCCBAE15790D760022990C /* main.m in Sources */, 238 | 4ADCCBB215790D760022990C /* AppDelegate.m in Sources */, 239 | 4ADCCBB515790D760022990C /* ViewController.m in Sources */, 240 | 4A4453811589EE9100B44ABB /* base64.c in Sources */, 241 | 4A4453821589EE9100B44ABB /* NSData+SRB64Additions.m in Sources */, 242 | 4A4453831589EE9100B44ABB /* SRWebSocket.m in Sources */, 243 | C9E391A215E2A1B00004693A /* SocketIOJSONSerialization.m in Sources */, 244 | 4AD96DF41680853E00D9E42D /* SocketIOPacket.m in Sources */, 245 | 4AD96DF816808B7900D9E42D /* SocketIOTransportWebsocket.m in Sources */, 246 | 4AD96DFC16822DE300D9E42D /* SocketIOTransportXHR.m in Sources */, 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | /* End PBXSourcesBuildPhase section */ 251 | 252 | /* Begin PBXVariantGroup section */ 253 | 4ADCCBAA15790D760022990C /* InfoPlist.strings */ = { 254 | isa = PBXVariantGroup; 255 | children = ( 256 | 4ADCCBAB15790D760022990C /* en */, 257 | ); 258 | name = InfoPlist.strings; 259 | sourceTree = ""; 260 | }; 261 | 4ADCCBB615790D760022990C /* ViewController.xib */ = { 262 | isa = PBXVariantGroup; 263 | children = ( 264 | 4ADCCBB715790D760022990C /* en */, 265 | ); 266 | name = ViewController.xib; 267 | sourceTree = ""; 268 | }; 269 | /* End PBXVariantGroup section */ 270 | 271 | /* Begin XCBuildConfiguration section */ 272 | 4ADCCBB915790D760022990C /* Debug */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | ALWAYS_SEARCH_USER_PATHS = NO; 276 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 277 | CLANG_ENABLE_OBJC_ARC = YES; 278 | CLANG_WARN_CONSTANT_CONVERSION = YES; 279 | CLANG_WARN_ENUM_CONVERSION = YES; 280 | CLANG_WARN_INT_CONVERSION = YES; 281 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 282 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 283 | COPY_PHASE_STRIP = NO; 284 | GCC_C_LANGUAGE_STANDARD = gnu99; 285 | GCC_DYNAMIC_NO_PIC = NO; 286 | GCC_OPTIMIZATION_LEVEL = 0; 287 | GCC_PREPROCESSOR_DEFINITIONS = ( 288 | "DEBUG=1", 289 | "$(inherited)", 290 | ); 291 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 292 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 294 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 295 | GCC_WARN_UNUSED_VARIABLE = YES; 296 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 297 | ONLY_ACTIVE_ARCH = YES; 298 | SDKROOT = iphoneos; 299 | }; 300 | name = Debug; 301 | }; 302 | 4ADCCBBA15790D760022990C /* Release */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 307 | CLANG_ENABLE_OBJC_ARC = YES; 308 | CLANG_WARN_CONSTANT_CONVERSION = YES; 309 | CLANG_WARN_ENUM_CONVERSION = YES; 310 | CLANG_WARN_INT_CONVERSION = YES; 311 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 312 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 313 | COPY_PHASE_STRIP = YES; 314 | GCC_C_LANGUAGE_STANDARD = gnu99; 315 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 316 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 317 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 318 | GCC_WARN_UNUSED_VARIABLE = YES; 319 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 320 | ONLY_ACTIVE_ARCH = YES; 321 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 322 | SDKROOT = iphoneos; 323 | VALIDATE_PRODUCT = YES; 324 | }; 325 | name = Release; 326 | }; 327 | 4ADCCBBC15790D760022990C /* Debug */ = { 328 | isa = XCBuildConfiguration; 329 | buildSettings = { 330 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 331 | GCC_PREFIX_HEADER = "SocketTesterARC/SocketTesterARC-Prefix.pch"; 332 | INFOPLIST_FILE = "SocketTesterARC/SocketTesterARC-Info.plist"; 333 | LIBRARY_SEARCH_PATHS = ( 334 | "$(inherited)", 335 | "\"$(SDKROOT)/usr/lib/system\"", 336 | ); 337 | ONLY_ACTIVE_ARCH = YES; 338 | PRODUCT_NAME = "$(TARGET_NAME)"; 339 | WRAPPER_EXTENSION = app; 340 | }; 341 | name = Debug; 342 | }; 343 | 4ADCCBBD15790D760022990C /* Release */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 347 | GCC_PREFIX_HEADER = "SocketTesterARC/SocketTesterARC-Prefix.pch"; 348 | INFOPLIST_FILE = "SocketTesterARC/SocketTesterARC-Info.plist"; 349 | LIBRARY_SEARCH_PATHS = ( 350 | "$(inherited)", 351 | "\"$(SDKROOT)/usr/lib/system\"", 352 | ); 353 | ONLY_ACTIVE_ARCH = YES; 354 | PRODUCT_NAME = "$(TARGET_NAME)"; 355 | WRAPPER_EXTENSION = app; 356 | }; 357 | name = Release; 358 | }; 359 | /* End XCBuildConfiguration section */ 360 | 361 | /* Begin XCConfigurationList section */ 362 | 4ADCCB9715790D760022990C /* Build configuration list for PBXProject "SocketTesterARC" */ = { 363 | isa = XCConfigurationList; 364 | buildConfigurations = ( 365 | 4ADCCBB915790D760022990C /* Debug */, 366 | 4ADCCBBA15790D760022990C /* Release */, 367 | ); 368 | defaultConfigurationIsVisible = 0; 369 | defaultConfigurationName = Release; 370 | }; 371 | 4ADCCBBB15790D760022990C /* Build configuration list for PBXNativeTarget "SocketTesterARC" */ = { 372 | isa = XCConfigurationList; 373 | buildConfigurations = ( 374 | 4ADCCBBC15790D760022990C /* Debug */, 375 | 4ADCCBBD15790D760022990C /* Release */, 376 | ); 377 | defaultConfigurationIsVisible = 0; 378 | defaultConfigurationName = Release; 379 | }; 380 | /* End XCConfigurationList section */ 381 | }; 382 | rootObject = 4ADCCB9415790D760022990C /* Project object */; 383 | } 384 | -------------------------------------------------------------------------------- /SocketTesterARC.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SocketTesterARC/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // SocketTesterARC 4 | // 5 | // Created by Kyeck Philipp on 01.06.12. 6 | // Copyright (c) 2012 beta_interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ViewController; 12 | 13 | @interface AppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @property (strong, nonatomic) ViewController *viewController; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /SocketTesterARC/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // SocketTesterARC 4 | // 5 | // Created by Kyeck Philipp on 01.06.12. 6 | // Copyright (c) 2012 beta_interactive. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import "ViewController.h" 12 | 13 | @implementation AppDelegate 14 | 15 | @synthesize window = _window; 16 | @synthesize viewController = _viewController; 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 19 | { 20 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 21 | // Override point for customization after application launch. 22 | self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; 23 | self.window.rootViewController = self.viewController; 24 | [self.window makeKeyAndVisible]; 25 | return YES; 26 | } 27 | 28 | - (void)applicationWillResignActive:(UIApplication *)application 29 | { 30 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 31 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 32 | } 33 | 34 | - (void)applicationDidEnterBackground:(UIApplication *)application 35 | { 36 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 38 | } 39 | 40 | - (void)applicationWillEnterForeground:(UIApplication *)application 41 | { 42 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 43 | } 44 | 45 | - (void)applicationDidBecomeActive:(UIApplication *)application 46 | { 47 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 48 | } 49 | 50 | - (void)applicationWillTerminate:(UIApplication *)application 51 | { 52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /SocketTesterARC/SocketTesterARC-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | de.beta-interactive.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /SocketTesterARC/SocketTesterARC-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'SocketTesterARC' target in the 'SocketTesterARC' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /SocketTesterARC/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // SocketTesterARC 4 | // 5 | // Created by Kyeck Philipp on 01.06.12. 6 | // Copyright (c) 2012 beta_interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SocketIO.h" 11 | 12 | @interface ViewController : UIViewController 13 | { 14 | SocketIO *socketIO; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SocketTesterARC/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // SocketTesterARC 4 | // 5 | // Created by Kyeck Philipp on 01.06.12. 6 | // Copyright (c) 2012 beta_interactive. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void) viewDidLoad 18 | { 19 | [super viewDidLoad]; 20 | 21 | // create socket.io client instance 22 | socketIO = [[SocketIO alloc] initWithDelegate:self]; 23 | 24 | // you can update the resource name of the handshake URL 25 | // see https://github.com/pkyeck/socket.IO-objc/pull/80 26 | // [socketIO setResourceName:@"whatever"]; 27 | 28 | // if you want to use https instead of http 29 | // socketIO.useSecure = YES; 30 | 31 | // pass cookie(s) to handshake endpoint (e.g. for auth) 32 | NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys: 33 | @"localhost", NSHTTPCookieDomain, 34 | @"/", NSHTTPCookiePath, 35 | @"auth", NSHTTPCookieName, 36 | @"56cdea636acdf132", NSHTTPCookieValue, 37 | nil]; 38 | NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:properties]; 39 | NSArray *cookies = [NSArray arrayWithObjects:cookie, nil]; 40 | 41 | socketIO.cookies = cookies; 42 | 43 | // connect to the socket.io server that is running locally at port 3000 44 | [socketIO connectToHost:@"localhost" onPort:3000]; 45 | } 46 | 47 | # pragma mark - 48 | # pragma mark socket.IO-objc delegate methods 49 | 50 | - (void) socketIODidConnect:(SocketIO *)socket 51 | { 52 | NSLog(@"socket.io connected."); 53 | } 54 | 55 | - (void) socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet 56 | { 57 | NSLog(@"didReceiveEvent()"); 58 | 59 | // test acknowledge 60 | SocketIOCallback cb = ^(id argsData) { 61 | NSDictionary *response = argsData; 62 | // do something with response 63 | NSLog(@"ack arrived: %@", response); 64 | 65 | // test forced disconnect 66 | [socketIO disconnectForced]; 67 | }; 68 | [socketIO sendMessage:@"hello back!" withAcknowledge:cb]; 69 | 70 | // test different event data types 71 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 72 | [dict setObject:@"test1" forKey:@"key1"]; 73 | [dict setObject:@"test2" forKey:@"key2"]; 74 | [socketIO sendEvent:@"welcome" withData:dict]; 75 | 76 | [socketIO sendEvent:@"welcome" withData:@"testWithString"]; 77 | 78 | NSArray *arr = [NSArray arrayWithObjects:@"test1", @"test2", nil]; 79 | [socketIO sendEvent:@"welcome" withData:arr]; 80 | } 81 | 82 | - (void) socketIO:(SocketIO *)socket onError:(NSError *)error 83 | { 84 | if ([error code] == SocketIOUnauthorized) { 85 | NSLog(@"not authorized"); 86 | } else { 87 | NSLog(@"onError() %@", error); 88 | } 89 | } 90 | 91 | 92 | - (void) socketIODidDisconnect:(SocketIO *)socket disconnectedWithError:(NSError *)error 93 | { 94 | NSLog(@"socket.io disconnected. did error occur? %@", error); 95 | } 96 | 97 | # pragma mark - 98 | 99 | - (void) viewDidUnload 100 | { 101 | [super viewDidUnload]; 102 | } 103 | 104 | - (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 105 | { 106 | return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); 107 | } 108 | 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /SocketTesterARC/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SocketTesterARC/en.lproj/ViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1296 5 | 11E53 6 | 2182 7 | 1138.47 8 | 569.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1181 12 | 13 | 14 | IBUIActivityIndicatorView 15 | IBUIView 16 | IBUISegmentedControl 17 | IBProxyObject 18 | 19 | 20 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 21 | 22 | 23 | PluginDependencyRecalculationVersion 24 | 25 | 26 | 27 | 28 | IBFilesOwner 29 | IBCocoaTouchFramework 30 | 31 | 32 | IBFirstResponder 33 | IBCocoaTouchFramework 34 | 35 | 36 | 37 | 274 38 | 39 | 40 | 41 | 292 42 | {{121, 165}, {37, 37}} 43 | 44 | 45 | 46 | _NS:9 47 | NO 48 | IBCocoaTouchFramework 49 | NO 50 | YES 51 | 0 52 | 53 | 54 | 55 | 292 56 | {{57, 294}, {207, 44}} 57 | 58 | 59 | _NS:9 60 | NO 61 | IBCocoaTouchFramework 62 | 2 63 | 0 64 | 65 | First 66 | Second 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | {0, 0} 78 | {0, 0} 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | {{0, 20}, {320, 460}} 87 | 88 | 89 | 90 | 91 | 3 92 | MC43NQA 93 | 94 | 2 95 | 96 | 97 | NO 98 | 99 | IBCocoaTouchFramework 100 | 101 | 102 | 103 | 104 | 105 | 106 | view 107 | 108 | 109 | 110 | 7 111 | 112 | 113 | 114 | 115 | 116 | 0 117 | 118 | 119 | 120 | 121 | 122 | -1 123 | 124 | 125 | File's Owner 126 | 127 | 128 | -2 129 | 130 | 131 | 132 | 133 | 6 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 10 143 | 144 | 145 | 146 | 147 | 11 148 | 149 | 150 | 151 | 152 | 153 | 154 | ViewController 155 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 156 | UIResponder 157 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 158 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 159 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 160 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 161 | 162 | 163 | 164 | 165 | 166 | 11 167 | 168 | 169 | 170 | 171 | ViewController 172 | UIViewController 173 | 174 | IBProjectSource 175 | ./Classes/ViewController.h 176 | 177 | 178 | 179 | 180 | 0 181 | IBCocoaTouchFramework 182 | 183 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 184 | 185 | 186 | YES 187 | 3 188 | 1181 189 | 190 | 191 | -------------------------------------------------------------------------------- /SocketTesterARC/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SocketTesterARC 4 | // 5 | // Created by Kyeck Philipp on 01.06.12. 6 | // Copyright (c) 2012 beta_interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /submodules/.gitignore: -------------------------------------------------------------------------------- 1 | # xcode noise 2 | build/* 3 | build 4 | *.pbxuser 5 | *.mode1v3 6 | *.mode2v3 7 | *.perspectivev3 8 | *.tmproj 9 | */*.pbxuser 10 | */*.mode1v3 11 | */*.mode2v3 12 | */*.perspectivev3 13 | */*.tmproj 14 | Build 15 | Products 16 | xcuserdata 17 | xcuserdata/* 18 | project.xcworkspace 19 | project.xcworkspace/* 20 | */project.xcworkspace 21 | */project.xcworkspace/* 22 | */xcuserdata 23 | DerivedData 24 | 25 | # osx noise 26 | .DS_Store 27 | profile 28 | 29 | # vim noise 30 | *.swp 31 | --------------------------------------------------------------------------------