title: Close connection when NSOutputStream has finished
body: <p>How can a connection be closed when the NSOutputStream has finished sending data?</p>
  
  <p>After searching around i have found that the event <code>NSStreamEventEndEncountered</code> is only called if the server drops the connection. not if the OutputStream has finished the data to send. </p>
  
  <p><code>StreamStatus</code> is Always returning 0 (connection closed) or 2 (connection open) but never 4 (writing data).</p>
  
  <p>since both methods mentioned above are not telling me enough about the write process i am not able to find a way do determine if the Stream is still writing or if it has finished and i can close the connection now. </p>
  
  <p>After 5 days of googleling and trying i am totally out of ideas... Any help appreciated. Thanks</p>
  
  <p>EDIT ADDED CODE AS REQUESTED:</p>
  
  <pre><code>- (void)startSend:(NSString *)filePath
  
  {
  
  BOOL                    success;
  
  NSURL *                 url;
  
  
  
  assert(filePath != nil);
  
  assert([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
  
  assert( [filePath.pathExtension isEqual:@"png"] || [filePath.pathExtension isEqual:@"jpg"] );
  
  
  
  assert(self.networkStream == nil);      // don't tap send twice in a row!
  
  assert(self.fileStream == nil);         // ditto
  
  
  
  // First get and check the URL.
  
  ...
  ....
  .....
  
  
  // If the URL is bogus, let the user know.  Otherwise kick off the connection.
  
  ...
  ....
  .....
  
  
  if ( ! success) {
  
      self.statusLabel.text = @"Invalid URL";
  
  } else {
  
  
  
      // Open a stream for the file we're going to send.  We do not open this stream; 
  
      // NSURLConnection will do it for us.
  
  
  
      self.fileStream = [NSInputStream inputStreamWithFileAtPath:filePath];
  
      assert(self.fileStream != nil);
  
  
  
      [self.fileStream open];
  
  
  
      // Open a CFFTPStream for the URL.
  
  
  
      self.networkStream = CFBridgingRelease(
  
          CFWriteStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) url)
  
      );
  
      assert(self.networkStream != nil);
  
  
  
      if ([self.usernameText.text length] != 0) {
  
          success = [self.networkStream setProperty:self.usernameText.text forKey:(id)kCFStreamPropertyFTPUserName];
  
          assert(success);
  
          success = [self.networkStream setProperty:self.passwordText.text forKey:(id)kCFStreamPropertyFTPPassword];
  
          assert(success);
  
      }
  
  
  
      self.networkStream.delegate = self;
  
      [self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  
      ///////******** LINE ADDED BY ME TO DISONNECT FROM FTP AFTER CLOSING CONNECTION *********////////////
  
      [self.networkStream setProperty:(id)kCFBooleanFalse forKey:(id)kCFStreamPropertyFTPAttemptPersistentConnection];
  
      ///////******** END LINE ADDED BY ME *********//////////// 
  
      [self.networkStream open];
  
  
  
      // Tell the UI we're sending.
  
  
  
      [self sendDidStart];
  
  }
  
  }
  
  
  
  - (void)stopSendWithStatus:(NSString *)statusString
  
  {
  
  if (self.networkStream != nil) {
  
      [self.networkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  
      self.networkStream.delegate = nil;
  
      [self.networkStream close];
  
      self.networkStream = nil;
  
  }
  
  if (self.fileStream != nil) {
  
      [self.fileStream close];
  
      self.fileStream = nil;
  
  }
  
  [self sendDidStopWithStatus:statusString];
  
  }
  
  
  
  - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
  
  // An NSStream delegate callback that's called when events happen on our 
  
  // network stream.
  
  {
  
  #pragma unused(aStream)
  
  assert(aStream == self.networkStream);
  
  
  
  switch (eventCode) {
  
      case NSStreamEventOpenCompleted: {
  
          [self updateStatus:@"Opened connection"];
  
      } break;
  
      case NSStreamEventHasBytesAvailable: {
  
          assert(NO);     // should never happen for the output stream
  
      } break;
  
      case NSStreamEventHasSpaceAvailable: {
  
          [self updateStatus:@"Sending"];
  
  
  
          // If we don't have any data buffered, go read the next chunk of data.
  
  
  
          if (self.bufferOffset == self.bufferLimit) {
  
              NSInteger   bytesRead;
  
  
  
              bytesRead = [self.fileStream read:self.buffer maxLength:kSendBufferSize];
  
  
  
              if (bytesRead == -1) {
  
                  [self stopSendWithStatus:@"File read error"];
  
              } else if (bytesRead == 0) {
  
                  [self stopSendWithStatus:nil];
  
              } else {
  
                  self.bufferOffset = 0;
  
                  self.bufferLimit  = bytesRead;
  
              }
  
          }
  
  
  
          // If we're not out of data completely, send the next chunk.
  
  
  
          if (self.bufferOffset != self.bufferLimit) {
  
              NSInteger   bytesWritten;
  
              bytesWritten = [self.networkStream write:&amp;self.buffer[self.bufferOffset] maxLength:self.bufferLimit - self.bufferOffset];
  
              assert(bytesWritten != 0);
  
              if (bytesWritten == -1) {
  
                  [self stopSendWithStatus:@"Network write error"];
  
              } else {
  
                  self.bufferOffset += bytesWritten;
  
              }
  
          }
  
      } break;
  
      case NSStreamEventErrorOccurred: {
  
          [self stopSendWithStatus:@"Stream open error"];
  
      } break;
  
      case NSStreamEventEndEncountered: {
  
          // FOR WHATEVER REASON THIS IS NEVER CALLED!!!!
  
      } break;
  
      default: {
  
          assert(NO);
  
      } break;
  
  }
  
  }
  </code></pre>