0

を作成し、それを から呼び出す にNSOutputStream渡します。操作では、ソケットに書き出せるようにポーリングしています。これは、ソケットに初めて書き出すときに正常に機能します。ただし、操作が戻った後、ソケットに再度書き込もうとすると、出力ソケットでスペースが使用可能になるのを無限に待っているため、書き込みは行われません。書き込むたびに出力ストリームを開いたり閉じたりしようとしましたが、同じ問題があります。NSOperationNSOperationQueuehasSpaceAvailable

init 関数で出力ストリームを開きます (これNSOutputStreamは Bluetooth から作成されます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];
}
4

1 に答える 1

0

ポーリングではなく、ストリームに実行ループスケジューリングを使用する必要があります。のドキュメントを-[EASession outputStream]引用してください:

このストリームはセッションオブジェクトによって自動的に提供されますが、関連するストリームイベントを受信する場合は、このストリームを構成する必要があります。stream:handleEvent:これを行うには、デリゲートメソッドを実装するストリームにデリゲートオブジェクトを割り当てます。次に、実行ループでストリームをスケジュールして、アプリケーションのスレッドの1つから非同期でデータを送信できるようにする必要があります。

于 2013-02-04T19:35:52.097 に答える