阻止与ios附件的通信
苹果似乎建议使用runloops与外部附件进行数据通信。然而,除非我遗漏了一些东西,否则runloop不太适合某些类型的通信 我们有一个-实验-附件,我们需要向其发送任意数量的字节(最多,比如1024),然后附件处理该数据(可变延迟,比如1ms到1000ms),然后从附件发送可变长度响应(最多1024字节) 我们希望开发一个静态库(框架),用于与附件通信。基本上,这个库将有一个函数,它将NSArray或NSMutableArray作为输入,并返回包含响应的NSArray或NSMutableArray 问题是,推荐的runloops策略不太适合这种类型的应用程序。在静态库函数中,在准备要传输的数据并安排传输之后,我们必须进入某种“等待”状态。但是,这种等待状态不能基于轮询方法(例如等待接收路由设置的-synchronized-variable),因为这样接收例程就永远无法执行(因为它们在同一个线程上) 如果我们不使用runloops,那么我们就不知道何时读取数据,因为我们不知道数据何时到达阻止与ios附件的通信,ios,objective-c,cocoa-touch,external-accessory,Ios,Objective C,Cocoa Touch,External Accessory,苹果似乎建议使用runloops与外部附件进行数据通信。然而,除非我遗漏了一些东西,否则runloop不太适合某些类型的通信 我们有一个-实验-附件,我们需要向其发送任意数量的字节(最多,比如1024),然后附件处理该数据(可变延迟,比如1ms到1000ms),然后从附件发送可变长度响应(最多1024字节) 我们希望开发一个静态库(框架),用于与附件通信。基本上,这个库将有一个函数,它将NSArray或NSMutableArray作为输入,并返回包含响应的NSArray或NSMutableArr
关于如何解决这个问题有什么想法或建议吗?有什么例子吗?这不是运行循环或外部附件问题。 这是一个日常的OOP问题 最好的方法是创建一个可以写入outputStream并等待响应的通信对象。 使用@protocols来实现这一点!(事件侦听器驱动的过程) 试试这个:
/* Define your protocol */
@protocol CommDelegate <NSObject>
-(void)byteReceived: (char) byte;
@end
@interface Comm <NSObject> {
[...]
id<CommDelegate> delegate;
}
@end
@property (nonatomic, retain) id<CommDelegate> delegate;
@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;
}
}
@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
首先,您必须将输入/输出流附加到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;
@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;
}
}
@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
你的应用程序控制器。h:
@interface MyApp : UIViewController <CommDelegate> {
Comm comm;
}
@end
希望这有帮助但在您的示例中,您在“currentRunLoop”上调度流,而不是在另一个线程上调度流。读写操作似乎也在主线程上执行。一个“runloop”在线程的空闲时间内运行,它没有阻塞。。。在这种情况下,当一个字节变为可用时,将触发一个通知(nsstreamventhasbytesavailable)。我可以使用“[stream read:&ch maxLength:1]”读取字节。此操作与从向量中读取一个字节一样快。是的,当然字节是在主线程中读取的,但是它没有阻塞。谢谢你的回答!无论如何,我没有说明我的评论背后的原因,对不起:P我并不是说你错了或者你的解决方案有问题,只是说“现在你可以通知代理(你的主线程)”有点误导,因为你已经在主线程上了:)