2013-11-04 20 views
3

似乎Apple建議使用runloops與外部附件進行數據通信。但是,除非我丟失了某些東西,runloops並不適合某些類型的通信。阻止與ios配件的通信

我們有一個-experimental-附件,我們需要發送任意數量的字節(最多1024),然後附件處理數據(可變延遲,比如1ms到1000ms之間) ,然後是附件中的可變長度響應(最多1024字節)。

我們想開發一個靜態庫(框架)來與附件進行通信。基本上,這個庫將有一個函數,它將NSArray或NSMutableArray作爲輸入,並返回包含響應的NSArray或NSMutableArray。

問題是推薦的runloops策略不適合這種類型的應用程序。在靜態庫函數中,在準備好待傳輸的數據並調度傳輸之後,我們必須進入某種「等待」狀態。然而,這種等待狀態不能基於輪詢方法(例如等待由接收路由設置的-synchronized-變量),因爲接收例程永遠不會執行(因爲它們在同一個線程上) 。

如果我們不使用runloops,那麼我們無法知道何時讀取數據,因爲我們不知道數據何時到達。

有關如何解決此問題的任何想法或建議?那裏有沒有例子?

回答

3

這不是一個runLoop或ExternalAccessories問題。 這是一個每日OOP問題。

最好的方法是創建一個可以寫入outputStream並等待響應的通信對象。 使用@協議來做到這一點! (事件監聽器驅動程序)

試試這個:

首先你必須輸入/輸出流附加到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 

希望這有助於!

+0

但在您的示例中,您正在調度'currentRunLoop'上的流,您並未在另一個線程上安排它們。讀取和寫入操作似乎也在主線程上執行。 –

+1

一個「runloop」運行在一個線程的空閒時間,它不會阻塞......在這種情況下,當一個字節變爲可用時,通知被觸發(NSStreamEventHasBytesAvailable)。我可以通過'[stream read:&ch maxLength:1];'來讀取字節。從一個向量讀取一個字節,此操作速度很快。當然,該字節是在主線程中讀取的,但不會阻塞。 –

+0

謝謝你的回答!無論如何,我沒有說明我的評論背後的原因,對不起:P我並不是說你錯了,或者你的解決方案有問題,但只是評論'現在你可以通知代表(你的主線程) '是有點誤導,因爲你已經在主線程:) –