3

Apple は、外部アクセサリとのデータ通信にランループを使用することを推奨しているようです。ただし、何かが欠けていない限り、ランループは特定の種類の通信にはあまり適していません。

実験的なアクセサリがあり、これに任意のバイト数 (たとえば 1024 まで) を送信する必要があり、その後にそのデータを処理するアクセサリ (可変遅延、たとえば 1ms から 1000ms の間) が続きます。アクセサリからの可変長応答 (最大 1024 バイト)。

アクセサリと通信するための静的ライブラリ (フレームワーク) を開発したいと考えています。基本的に、このライブラリには、NSArray または NSMutableArray を入力として取り、応答を含む NSArray または NSMutableArray を返す関数があります。

問題は、ランループの推奨戦略がこのタイプのアプリケーションにはあまり適していないことです。静的ライブラリ関数では、送信するデータを準備し、送信をスケジュールした後、何らかの「待機」状態に入る必要があります。ただし、この待機状態は、ポーリング方法 (受信ルーティングによって設定される同期変数を待機するなど) に基づくことはできません。これは、受信ルーチンが実行されないためです (同じスレッド上にあるため)。 .

ランループを使用しない場合、データがいつ到着するかわからないため、いつデータを読み取るかを知ることができません。

この問題にアプローチする方法に関するアイデアや推奨事項はありますか? そこに例はありますか?

4

1 に答える 1

3

これは runLoop または ExternalAccessories の問題ではありません。これは日常的な OOP 問題です。

最善の方法は、outputStream に書き込み、応答を待機できる Communication オブジェクトを作成することです。これを行うには @protocols を使用してください。(イベントリスナー主導の手続き)

これを試して:

まず、入出力ストリームを runLoop にアタッチする必要があります。

[[session inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[session inputStream] open];
[[session outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[session outputStream] open];

彼らの代理人になります:

[[session outputStream] setDelegate:self];
[[session inputStream] setDelegate:self];

デリゲートになったら、このメソッドを実装する必要があります。

-(void)stream:handleEvent:{};

これは、データをストリームに書き出すコマンドです。

/* data is a NSData containing data to transmit. */
[[session outputStream] write:(uint8_t *)[data bytes] maxLength:[data length]];

これはコードの例です (セッションを作成したら、予想される答えはバイトです):

Comm.h:

/* Define your protocol */
@protocol CommDelegate <NSObject>
    -(void)byteReceived: (char) byte;
@end

@interface Comm <NSObject> {
    [...]
    id<CommDelegate> delegate;
}
@end

@property (nonatomic, retain) id<CommDelegate> delegate;

Comm.m:

@implementation Comm

[...]
-(id)init {
    [...]
    delegate = nil;
    [...]
}

-(void)write: (NSData *) data {
    [[session outputStream] write:(uint8_t *)[data bytes] maxLength:[data length]];
}

-(void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)_event {
    switch (_event)
    {
        case NSStreamEventHasBytesAvailable:
            /* This part will be executed every time your rx buffer contains at least 1 byte */
            switch(state) {
                uint8_t ch;
                /* Read byte per byte */
                [stream read:&ch maxLength:1];
                /* now ch contains a byte from your MFI device
                ** and 'read' function decrease the length of the rx buffer by -1 */

                /* Now you can notify this to the delegate
                */
                if(self.delegate != nil)
                    [delegate byteReceived: ch];
            }
            break;
    }
}

your_app_controller.h:

@interface MyApp : UIViewController <CommDelegate> {
    Comm comm;
}
@end

your_app_controller.m:

@implementation MyApp

-(id)init {
    [...]
    comm = [[Comm alloc] init];
    [comm setDelegate: self];   /* Now your thread is listening your communication. */
}

-(void)write {
    byte out = 'X';
    [comm write: [NSData dataWithBytes: &out length: 1]];
}

-(void)bytereceived:(char)reply {
    if(reply == 'Y') {
        [self write];
        //[self performSelectorInBackground:@selector(write) withObject:nil]; IT'S BETTER!!!
    }

}

@end

お役に立てれば!

于 2013-11-14T14:31:10.930 に答える