在第二次NSOperation尝试写入后,NSOutputStream始终在等待可用空间

时间:2013-02-04 18:55:00

标签: objective-c nsoperation nsoperationqueue nsoutputstream

我正在创建一个NSOutputStream并将其传递给NSOperation,我是从NSOperationQueue调用的。在操作中,我正在轮询hasSpaceAvailable,以便我可以写出套接字。这在第一次写入套接字时工作正常。然而,在操作返回之后,我尝试再次写入套接字,写入永远不会通过,因为我无限地等待输出套接字中的空间可用。我每次写的时候都尝试打开/关闭输出流,但是遇到了同样的问题。

我在init函数中打开输出流(NSOutputStream是从蓝牙EASession创建的:

_commandSession = [[EASession alloc] initWithAccessory:self.selectedAccessory forProtocol:commandProtocolString];
_commandOutputStream = [_commandSession outputStream];
[_commandOutputStream open];

我还在init中创建了操作队列:

_senderOperationQueue = [[NSOperationQueue alloc] init];
_senderOperationQueue.name = @"Send Queue";
_senderOperationQueue.maxConcurrentOperationCount = 1;

我有一个文本字段,其中包含我想通过输出流发送的数据。每次单击发送按钮时都会调用此函数:

-(void)sendCommandData:(NSData *)buf
{
  _commandSendOperation =[[SenderOperation alloc] initWithStream:_commandOutputStream data:buf delegate:self];
  [_senderOperationQueue addOperation:_commandSendOperation];
}

这是我的操作代码的样子: (SenderOperation.h

#import <Foundation/Foundation.h>

@protocol SenderOperationDelegate;

@interface SenderOperation : NSOperation
{
    NSOutputStream *_stream;
    NSData *_sendData;
}

@property (nonatomic, assign) id <SenderOperationDelegate> delegate;
@property (nonatomic, retain) NSOutputStream *stream;
@property (nonatomic, retain) NSData *sendData;

- (id)initWithStream:(NSOutputStream *)stream data:(NSData *)buf delegate:(id<SenderOperationDelegate>)theDelegate;

@end

// Delegate to notify main thread the completion of a BT input buffer stream
@protocol SenderOperationDelegate <NSObject>
-(void)sendComplete:(SenderOperation *)sender;
@end

SenderOperation.m

#import "SenderOperation.h"

@implementation SenderOperation

@synthesize delegate = _delegate;
@synthesize stream = _stream;
@synthesize sendData = _sendData;

- (id)initWithStream:(NSOutputStream *)stream data:(NSData *)buf delegate:(id<SenderOperationDelegate>)theDelegate
{
  if (self = [super init])
  {
    self.delegate = theDelegate;
    self.stream = stream;
    self.sendData = buf;
  }
  return self;
}

#define MAX_PACKET_SIZE 20

- (void)main
{
  if (self.isCancelled)
    return;

// total length of the data packet we need to send
int totalLength = [_sendData length];

// length of packet to send (given our upper bound)
int len = (totalLength <= MAX_PACKET_SIZE) ? totalLength:MAX_PACKET_SIZE;

// stream write response
int streamWriteResponse;

// bytes already written out to the output stream
int bytesWritten = 0;

while (1)
{
 if (!len) break;

 if ([self.stream hasSpaceAvailable])
 {
   streamWriteResponse = [self.stream write:[self.sendData bytes] maxLength:len];

   if (streamWriteResponse == -1)
   {
    break;
   }

  bytesWritten += streamWriteResponse;

  // update the data buffer with left over data that needs to be written
  if (totalLength - bytesWritten)
    self.sendData = [self.sendData subdataWithRange:NSMakeRange(bytesWritten, totalLength - bytesWritten)];

  // update length of next data packet write
  len = (totalLength - bytesWritten) >= MAX_PACKET_SIZE ? MAX_PACKET_SIZE : (totalLength - bytesWritten);
  }
}

[(NSObject *)self.delegate performSelectorOnMainThread:@selector(sendComplete:) withObject:self waitUntilDone:NO];
}

1 个答案:

答案 0 :(得分:0)

您需要对流使用运行循环调度,而不是轮询。 Quoth the docs for -[EASession outputStream]

  

此流由会话对象自动提供,但如果要接收任何关联的流事件,则必须对其进行配置。您可以通过将委托对象分配给实现stream:handleEvent:委托方法的流来完成此操作。然后,您必须在运行循环中调度流,以便它可以从您的应用程序的一个线程异步发送数据。