阻止与ios附件的通信 [英] Blocking communication with ios accessory

查看:133
本文介绍了阻止与ios附件的通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎Apple建议使用runloop与外部附件进行数据通信。但是,除非我缺少某些东西,runloops不是非常适合某些类型的通信。



我们有一个实验附件,我们需要发送一个任意字节数(直到1024),其后是辅助处理数据(可变延迟,例如在1ms到1000ms之间),随后是来自附件的可变长度响应(最多1024字节)。



我们想开发一个静态库(框架)与附件进行通信。基本上,这个库将有一个函数,它接受一个NSArray或NSMutableArray作为输入,并返回包含响应的NSArray或NSMutableArray。



问题是推荐runloops的策略不是非常适合这种类型的应用程序。在静态库函数中,在准备要发送的数据和调度发送之后,我们必须进入某种等待状态。然而,这种等待状态不能基于轮询方法(例如等待由接收路由设置的同步变量),因为接收例程从不会执行(因为它们在同一线程上) 。



如果我们不使用runloops,那么我们不知道何时读取数据,因为我们不知道数据何时到达。 p>

有关如何处理此问题的任何想法或建议?有没有什么例子?

解决方案

这不是一个runLoop或ExternalAccessories问题。
这是一个每日OOP问题。



最好的方法是创建一个Communication对象,它可以写入outputStream并等待响应。
使用@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是包含要发送的数据的NSData。 * / 
[[session outputStream] write:(uint8_t *)[data bytes] maxLength:[data length]];

这是一个示例代码,(一旦你创建了会话,而我们期望的答案是一个字节):

 <$ c 

$ c> / *定义你的协议* /
@protocol CommDelegate< NSObject>
- (void)byteReceived:(char)byte;
@end

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

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

在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 :
/ *这部分将在每次你的rx缓冲区包含至少1个字节时执行* /
switch(state){
uint8_t ch;
/ *每字节读取字节* /
[流读取:& ch maxLength:1];
/ *现在ch包含您的MFI设备的一个字节
**和'read'函数将rx缓冲区的长度减少-1 * /

/ *现在你可以通知这个代理
* /
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]; / *现在你的线程正在侦听你的通信。 * /
}

- (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];好多了!!!
}

}

@end

希望这有助于!


It appears that Apple recommends using runloops for data communications with an external accessory. However, unless I am missing something, runloops are not very suitable for certain types of communications.

We have an -experimental- accessory, to which we need to send an arbitrary number of bytes (up to, say 1024), which is followed by the accessory processing that data (variable delay, say between 1ms to 1000ms), followed by a variable length response (upto 1024 bytes) from the accessory.

We would like to develop a static library (framework) for communicating with the accessory. Basically, this library will have a function, which takes an NSArray or NSMutableArray as an input, and returns NSArray or NSMutableArray, containing the response.

The problem is that the recommended strategy of runloops isn't very suitable for this type of application. In the static library function, after preparing the data to be transmitted and scheduling the transmission, we have to enter some sort of "wait" state. However, this wait state can not be based on a polling method (such as waiting on a -synchronized- variable to be set by the receive routing), because then the receive routine never gets to execute (since they are on the same thread).

If we don't use runloops, then we can not know when to read the data, because we don't know when the data will be arriving.

Any ideas or recommendations on how to approach this problem? Are there any examples out there?

解决方案

This is not a runLoop or ExternalAccessories problem. This is a daily OOP problem.

The best way is to create a Communication object that can write to the outputStream and wait for response. Use @protocols to do this! (Event-Listener driven procedure)

TRY THIS:

First of all you have to attach input/output streams to a runLoop:

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

Become their delegate:

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

Once you become delegate you have to implement this method:

-(void)stream:handleEvent:{};

This is the command to write out data to a stream:

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

This is an example code, (once you have session created, whereas the answer we expect is a byte):

in 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;

In 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

Hope this helps!

这篇关于阻止与ios附件的通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆