NSInputStream does not call a delegate (stream: handleEvent :)

I searched the website for a long time ... I did not find the answer to the question, so I decided to publish it here. I am trying to establish a connection to an NNTP server using NSStream.

In a test program, I open streams and send a message. The delegate method ( stream:handleEvent: is called twice for the output stream ( NSStreamEventOpenCompleted , NSStreamEventHasSpaceAvailable ), but never for the input stream!

Why does the input never call a delegate? Any ideas?

Basically, the code is as follows:

init and open threads:

 CFReadStreamRef tmpiStream; CFWriteStreamRef tmpoStream; CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)SERVER, PORT, &tmpiStream, &tmpoStream); iStream = (__bridge NSInputStream *) tmpiStream; oStream = (__bridge NSOutputStream *)tmpoStream; [iStream setDelegate:self]; [oStream setDelegate:self]; [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [oStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [iStream open]; [oStream open]; 

send a message:

 NSData *data = [[NSData alloc] initWithData:[messageString dataUsingEncoding:NSASCIIStringEncoding]]; [oStream write:[data bytes] maxLength:[data length]]; 

receive messages:

 -(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { NSLog(@"EventCode: %i", eventCode); //switch-case-statement...(using constants - NSStreamEventOpenCompleted...) } 

The class that contains this code inherits from NSObjects and implements NSStreamDelegate . (iOS5 with ARC)

Thanks for any help!

EDIT: I just tried polling after opening threads like this - it works:

 while (![iStream hasBytesAvailable]) {} uint8_t buffer[1024]; int len; NSString *str = @""; while ([iStream hasBytesAvailable]) { len = [iStream read:buffer maxLength:sizeof(buffer)]; if (len > 0) { NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSISOLatin1StringEncoding]; if (output != nil) { str = [str stringByAppendingString:output]; } } } NSLog(@"Response: %@", str); 

But of course I still need a better (asynchronous) solution;)

+4
source share
3 answers

Do you allow the launch cycle to start in default mode?

Try checking the status of the input stream ( -streamStatus ).

Is anything written to the console?

You claim that the delegate method is called for the output stream, but your NSLog() call does not register the stream. Are you sure?

Finally, this is __bridge_transfer , but you must use the __bridge_transfer if you want to transfer ownership of the Core Foundation ARC stream objects. Even better, use CFBridgingRelease() , as this has obvious symmetry with Create in the function name. If there are no CFRelease() calls that you did not show, then existing code flows in streams.

0
source

I had the same problem, and I realized that I accidentally called

 [iStream setDelegate:self] 

before i created iStream.

0
source

I found your answer here, I have the same problem. Your answer worked for me, but I think this works better:

How to use delegate in NSStream?

To quote it:

The run loop does not work long enough for the delegate method to be called.

Add

 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]]; 

immediately after opening the stream. This is only necessary in a program without a GUI - otherwise the loop cycle will be deployed for you.

So mine looks like this:

 [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [self.inputStream open]; [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:30.0]]; 

Edited: Then, when you have data, for example, I have all my data, when NSStreamEventEndEncountered is encountered in the delegate method thread: handleEvent I put this:

 [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; CFRunLoopStop(CFRunLoopGetCurrent()); [theStream close]; 

Ends the startup cycle to 30.0, or at least you installed it. This will be the same as your answer if your code was in NSStreamHasBytesAvailable.

This allows me to still use the delegate methods and maintain a startup loop until the download is complete without missing the delegate method all together.

-1
source

Source: https://habr.com/ru/post/1416066/


All Articles