40868

How to use NSInputStream and NSOutputStream

Question:

I am trying to create a simple multiplayer turn-based game between iPhones. Right now all I want to do is pass in some string to my method, and have the method send the string through the NSOutputStream. I think I have properly connected my NSNetServices using NSNetServiceBrowser. Once they connect, my NSNetServiceDelegate has netService:didAcceptConnectionWithInputStream:outputStream: called, which should give me my i/o NSStream pair. My method looks like this:

-(void)netService:(NSNetService *)sender didAcceptConnectionWithInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream{ [self.myNet getInputStream:&inputStream outputStream:&outputStream]; self.inStream = inputStream; self.outStream = outputStream; [self.inStream setDelegate:self]; [self.inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [self.inStream open]; }

I think I have correctly set up NSInputStream. I also have a delegate for NSStream which is implementing stream:handleEvent:

It looks like this:

-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{ NSInputStream *inStream = (NSInputStream *)aStream; BOOL shouldClose = NO; switch(eventCode) { case NSStreamEventEndEncountered: shouldClose = YES; // If all data hasn't been read, fall through to the "has bytes" event if(![inStream hasBytesAvailable]) break; case NSStreamEventHasBytesAvailable: ; // We need a semicolon here before we can declare local variables uint8_t *buffer; NSUInteger length; BOOL freeBuffer = NO; // The stream has data. Try to get its internal buffer instead of creating one if(![inStream getBuffer:&buffer length:&length]) { // The stream couldn't provide its internal buffer. We have to make one ourselves buffer = malloc(BUFFER_LEN * sizeof(uint8_t)); freeBuffer = YES; NSInteger result = [inStream read:buffer maxLength:BUFFER_LEN]; if(result < 0) { // error copying to buffer break; } length = result; } // length bytes of data in buffer if(freeBuffer) free(buffer); break; case NSStreamEventErrorOccurred: // some other error shouldClose = YES; break; case NSStreamEventHasSpaceAvailable: break; case NSStreamEventNone: break; case NSStreamEventOpenCompleted: break; } if(shouldClose){ [inStream close]; } }

I took that code from: <a href="https://stackoverflow.com/questions/6685785/stream-to-get-data-nsinputstream" rel="nofollow">this page</a>. In that code, aStream should be self.inStream. I have looked at pages describing what to do for NSOutputStream, but none of them seem to be geared at a beginner like me. I have a few questions. Firstly, how do I set up a method that I pass the data in (NSData or maybe an NSString) and it sends it out through self.outStream. I would prefer an answer that explains the code, rather than just giving it to me. Secondly, should I open both of my streams in netService:didAcceptConnectionWithInputStream:outputStream:, and should I also scheduleInRunLoop the NSOutputStreamself.outStream`. Finally, am I doing everything wrong?

Thanks for your answers. Also this is my first question, so any constructive criticism is welcomed.

Answer1:

To write to output stream, check stream has space available and write data using

- (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)length

So, code may be like following.

if ( self.outStream.hasSpaceAvailable ) [ self.outStream write:... maxLength: ];

If output stream doesn't have space available, later

-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode

method of the delegate of output stream would be called with eventCode = NSStreamEventHasSpaceAvailable.

You should open output stream and schedule it in netService:didAcceptConnectionWithInputStream:outputStream or when you receive NSStreamEventOpenCompleted of input stream. Both are OK.

If you don't want writing block thread, you need to prepare queue.

So code is like following

NSMutableData* uQueue; NSInputStream* uIStream; NSOutputStream* uOStream; : : : uIStream.delegate = self; uOStream.delegate = self; [ uIStream scheduleInRunLoop:NSRunLoop.currentRunLoop forMode:NSDefaultRunLoopMode ]; [ uOStream scheduleInRunLoop:NSRunLoop.currentRunLoop forMode:NSDefaultRunLoopMode ]; [ uIStream open ]; [ uOStream open ]; uQueue = NSMutableData.data; : : : - (void) Send { if ( uQueue.length ) { NSInteger wLength = [ uOStream write:(const uint8_t*)uQueue.bytes maxLength:uQueue.length ]; if ( wLength > 0 ) [ uQueue replaceBytesInRange:NSMakeRange( 0, wLength ) withBytes:NULL length:0 ]; } } - (void) Write:(NSData*)p { [ uQueue appendData:p ]; if ( uOStream.hasSpaceAvailable ) [ self Send ]; } - (void) stream:(NSStream*)pS handleEvent:(NSStreamEvent)p { switch( p ) { : : : case NSStreamEventHasSpaceAvailable: [ self Send ]; break; } }

Recommend

  • Downsampling pcm/wav audio from 22khz to 8khz
  • Convert all images in directory to .mp4 using ffmpeg and a timestamp order
  • IOS Stream Socket
  • Extracting data from 2 tables
  • window event is not working in FireFox
  • Recovering a lost connection using sockets
  • ol.interaction.Select gives an error on ol.source.VectorTile
  • How to annotation order field when using XStream on Android?
  • clearcase rebase permission to specific person
  • How to implement AutoPlay for Windows 7/8
  • Suddenly unable to export to war file from eclipse
  • C# Dictionary ContainsKey
  • How to map childs/parent class with petapoco?
  • Getting push notification payload when user opens app manually after push has been received in the b
  • Change color of row programmatically in WatchKit
  • Linked list in C, no member error
  • Conditional serialization with protobuf-net
  • Ambiguous action methods in MVC 2
  • Can someone explain the exact use of interfaces in C#?
  • Auto Height of UICollectionView inside UITableViewCell
  • Member function pointer cast, from Derived to Base class
  • Is the Go HTTP handler goroutine expected to exit immediately in this case?
  • how to save bool value in KeychainItemWrapper
  • Load 24 bit TGA
  • PHP file_exists() anomaly
  • Generate a unique string based on a pair of strings
  • Deleting a widget from QTableView
  • Unzip archive in .Net CORE 1.0
  • multidatatrigger with multibinding in ControlTemplate.Triggers
  • Streaming screenshots over WebRTC as a video stream from iOS
  • Is there a parser equivalent of 'fragment' marking in ANTLR4?
  • Hide HTML elements without javascript, only CSS
  • Build Successful but not running on simulator
  • Copy to all folders batch file?
  • Play WS (2.2.1): post/put large request
  • Moving mysql files across servers
  • Bad request using file_get_contents for PUT request in PHP
  • How to pass list parameters for each object using Spring MVC?
  • Setting background image for body element in xhtml (for different monitors and resolutions)
  • JaxB to read class hierarchy