I create a MySocketClient class which implements NSStreamDelegate, and implements the method - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
and then call the bellow function to connect the server:
- (void)connectToHost:(NSString *)host onPort:(UInt32)port{
NSLog(@"will connect...");
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
_inputStream = (__bridge NSInputStream *)readStream;
_outputStream = (__bridge NSOutputStream *)writeStream;
_inputStream.delegate = self;
_inputStream.delegate = self;
[_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_inputStream open];
[_outputStream open];
}
It is great to connect my server, but the delegate method:
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
not called.
The 'connectToHost' is called in the method - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
of AppDelegate.m file as bellow shown:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ GoEasySocketClient *client = [[GoEasySocketClient alloc] init]; [client connectToHost:@"myhost" onPort:myport]; });
But the strange thing is if I use the AppDelegate as the NSStreamDelegate, and implement the method - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
and when I call connectToHost
method, the delegate method - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
will be called and the eventCode is NSStreamEventOpenCompleted
.
As you use the second thread you should run your own run loop according to apple documentation. So in your case it should be as follows:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
GoEasySocketClient *client = [[GoEasySocketClient alloc] init];
[client connectToHost:@"myhost" onPort:myport];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
});
Or you can use [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]]
instead of [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]
.
The only difference is that the first one "returns after either the first input source is processed or limitDate is reached" and
other one "runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking runMode:beforeDate: until the specified expiration date".
I’ve tried the first one with NSURLConnection and it works perfectly.
You can also use main thread’s run loop. In this case you should change code as follows:
[_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
Regarding your question:
But the strange thing is if I use the AppDelegate as the NSStreamDelegate, and implement the method - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode and when I call connectToHost method, the delegate method - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode will be called and the eventCode is NSStreamEventOpenCompleted.
It happens because you call connectToHost method from the main thread with its own run loop. This run loop starts automatically during app launch.