Q:

How do I implement a timeout / wait for an NSStream to effectively make method synchronous

I have an input stream and output stream for a bluetooth connected accessory
I want to achieve the following:
write data to outputStream
wait until data received on inputStream OR until 10 seconds pass
if inputStream data arrived return data
else return nil
I tried to implement this like so:
- (APDUResponse *)sendCommandAndWaitForResponse:(NSData *)request {
  APDUResponse * result;
  if (!deviceIsBusy && request != Nil) {
    deviceIsBusy = YES;
    timedOut = NO;
    responseReceived = NO;
    if ([[mySes outputStream] hasSpaceAvailable]) {
      [NSThread detachNewThreadSelector:@selector(startTimeout) toTarget:self withObject:nil];
      [[mySes outputStream] write:[request bytes] maxLength:[request length]];
      while (!timedOut && !responseReceived) {
        sleep(2);
        NSLog(@"tick");
      }
      if (responseReceived && response !=nil) {
        result = response;
        response = nil;
      }
      [myTimer invalidate];
      myTimer = nil;
    }
  }
  deviceIsBusy = NO;
  return result;
}

- (void) startTimeout {
  NSLog(@"start Timeout");
  myTimer = [NSTimer timerWithTimeInterval:10.0 target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES];
  [[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];
}

- (void)timerFireMethod:(NSTimer *)timer {
  NSLog(@"fired");
  timedOut = YES;
}

- (void)stream:(NSStream*)stream handleEvent:(NSStreamEvent)streamEvent
{
  switch (streamEvent)
  {
    case NSStreamEventHasBytesAvailable:
      // Process the incoming stream data.
      if(stream == [mySes inputStream])
      {
        uint8_t buf[1024];
        unsigned int len = 0;
        len = [[mySes inputStream] read:buf maxLength:1024];
        if(len) {
          _data = [[NSMutableData alloc] init];
          [_data appendBytes:(const void *)buf length:len];
          NSLog(@"Response: %@", [_data description]);
          response = [[APDUResponse alloc] initWithData:_data];
          responseReceived = YES;
        } else {
          NSLog(@"no buffer!");
        }
      }
      break;
     ... //code not relevant 
  }
}

So the theory was to have an NSTimer running on a separate thread that would set a boolean when it fired, then also have the handleEvent delegate method set another boolean if data is received. 
In the method we have a while loop with a sleep that will cease when one of these bools is set.
The problem I am having is that in the 'timeout scenario' my timerFireMethod is not getting called. My gut feeling is that I am not actually correctly setting the timer on a separate thread.
Can anyone see what is going wrong here or suggest a better implementation for the requirement above?

A:

Instead to impose an inappropriate synchronous approach for an inherently asynchronous problem, make your method sendCommandAndWaitForResponse asynchronous.
It's possible to wrap the "stream write" task into an asynchronous operation/task/method. For example, you might end with a concurrent subclass of NSOperation with the following interface:
typedef void (^DataToStreamCopier_completion_t)(id result);

@interface DataToStreamCopier : NSOperation

- (id) initWithData:(NSData*)sourceData
  destinationStream:(NSOutputStream*)destinationStream
         completion:(DataToStreamCopier_completion_t)completionHandler;

@property (nonatomic) NSThread* workerThread;
@property (nonatomic, copy) NSString* runLoopMode;
@property (atomic, readonly) long long totalBytesCopied;

// NSOperation
- (void) start;
- (void) cancel;
@property (nonatomic, readonly) BOOL isCancelled;
@property (nonatomic, readonly) BOOL isExecuting;
@property (nonatomic, readonly) BOOL isFinished;

@end

You can implement a "timeout" feature utilizing the cancel method.
Your method sendCommandAndWaitForResponse: becomes asynchronous with a completion handler:
- (void)sendCommand:(NSData *)request 
         completion:(DataToStreamCopier_completion_t)completionHandler
{
    DataToStreamCopier* op = [DataToStreamCopier initWithData:request 
                                            destinationStream:self.outputStream 
                                                   completion:completionHandler];
   [op start];

   // setup timeout with block:  ^{ [op cancel]; }
   ...
}

Usage:
[self sendCommand:request completion:^(id result) {
    if ([result isKindOfClass[NSError error]]) {
        NSLog(@"Error: %@", error);
    }
    else {
        // execute on a certain execution context (main thread) if required:
        dispatch_async(dispatch_get_main_queue(), ^{
            APDUResponse* response = result;
            ...    
        });
    }
}];

Caveat:
Unfortunately, implementing a concurrent NSOperation subclass properly with an underlying task employing a run loop isn't that trivial as it should be. There will arise subtle concurrency issues which force you to use synchronization primitives like locks or dispatch queues and a few other tricks to make it really reliable.
Luckily, wrapping any Run Loop task into a concurrent NSOperation subclass requires basically the same "boiler plate" code. So, once you have a generic solution, the coding effort is just copy/past from a "template" and then tailor the code for your specific purpose. 
Alternative Solution:
Strictly, you don't even need a subclass of NSOperation if you don't plan to put a number of those tasks into a NSOperationQueue. A concurrent operation can be simply started with sending it the start method - there is no NSOperationQueue required.  Then, not using a subclass of NSOperation can make your own implementation simpler, since subclassing NSOperation itself has its own subtleties.
However, you actually need an "operation object" which wraps your Run Loop driving a NSStream object, since the implementation requires to hold state, which cannot be accomplished in a simple asynchronous method.
So, you can use any custom class which can be viewed as an asynchronous operation having a start and cancel method and having a mechanism to notify the call-site when the underlying task is finished.
There are also more powerful means to notify the call-site than completion handlers. For example: promises or futures (see wiki article Futures and promises). 
Assuming you implemented your own "asynchronous operation" class with a Promise as a means to notify the call-site, e.g.: 
@interface WriteDataToStreamOperation : AsyncOperation

- (void) start;
- (void) cancel;

@property (nonatomic, readonly) BOOL isCancelled;
@property (nonatomic, readonly) BOOL isExecuting;
@property (nonatomic, readonly) BOOL isFinished;
@property (nonatomic, readonly) Promise* promise;

@end

your original problem will look much more "synchronous" - albeit sill being asynchronous:
Your sendCommand method becomes:
Note: assumes a certain implementation of a Promise class:
- (Promise*) sendCommand:(NSData *)command {
    WriteDataToStreamOperation* op = 
     [[WriteDataToStreamOperation alloc] initWithData:command 
                                         outputStream:self.outputStream];
    [op start];
    Promise* promise = op.promise;
    [promise setTimeout:100]; // time out after 100 seconds
    return promise;
}

Note: the promise has set a "timeout". This is basically registering a timer and a handler. If the timer fires before the promise gets resolved by the underlying task, the timer block resolves the promise with a timeout error. How (and IF) this is implemented depends on the Promise library. (Here, I'm assuming the RXPromise library, where I'm the author. Other implementation may also implement such a feature).
Usage:
[self sendCommand:request].then(^id(APDUResponse* response) {
    // do something with the response
    ...
    return  ...;  // returns the result of the handler
}, 
^id(NSError*error) {
    // A Stream error or a timeout error
    NSLog(@"Error: %@", error);
    return nil;  // returns nothing
});

Alternative Usage:
You may set the timeout in a different way. Now, suppose we didn't set a timeout within the sendCommand: method.
We can set a timeout "outside":
Promise* promise = [self sendCommand:request];
[promise setTimeout:100];
promise.then(^id(APDUResponse* response) {
    // do something with the response
    ...
    return  ...;  // returns the result of the handler
}, 
^id(NSError*error) {
    // A Stream error or a timeout error
    NSLog(@"Error: %@", error);
    return nil;  // returns nothing
});

Making the asynchronous method synchronous
Usually, you don't need to and shouldn't "convert" an asynchronous method to some synchronous method in your application code. This always leads to suboptimal and inefficient code which unnecessarily consumes system resources, like threads. 
Nonetheless, you may want to do this in Unit Tests where it makes sense:
Example for "synchronizing" asynchronous methods in Unit Tests
When testing your implementations, you frequently want to "wait" (yes synchronously) for a result. The fact that your underlying task is actually executing on a Run Loop, possibly on the same thread where you want to wait for the result, doesn't make the solution simpler.
However, you can accomplish this easily with RXPromise library utilizing the runLoopWait method which effectively enters a run loop and waits there for the promise to be resolved:
-(void) testSendingCommandShouldReturnResponseBeforeTimeout10 {
    Promise* promise = [self sendCommand:request];
    [promise setTimeout:10];
    [promise.then(^id(APDUResponse* response) {
        // do something with the response
        XCTAssertNotNil(response);            
        return  ...;  // returns the result of the handler
    }, 
    ^id(NSError*error) {
         // A Stream error or a timeout error
        XCTestFail(@"failed with error: %@", error);
        return nil;  // returns nothing

    }) runLoopWait];  // "wait" on the run loop
}

Here, method runLoopWait will enter a run loop, and wait for the promise to be resolved, either by a timeout error or when the underlying task has resolved the promise. The promise will not block the main thread and not poll the run loop. It will just leave the run loop when the promise has been resolved. Other run loop events will be processed as usual. 
Note: You can safely call testSendingCommandShouldReturnResponseBeforeTimeout10 from the main thread without blocking it. And this is absolutely necessary, since your Stream delegate methods may execute on the main thread, too!
There are other approaches usually found in Unit testing libraries which provide a similar feature to "wait" for the result of an asynchronous method or operation while entering a run loop.
Other approaches to "wait" for an eventual result of an asynchronous method or operation are not recommended. These usually will dispatch the method to a private thread and then block it until the result is available.
Useful resources
Code snippet (on Gist) for an operation like class which copies a stream into another stream utilizing Promises:
RXStreamToStreamCopier

