- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有蓝牙连接附件的输入流和输出流
我要实现以下目标:
将数据写入outputStream
等待,直到在inputStream上接收到数据,或者直到10秒钟过去
如果inputStream数据到达,则返回数据
否则返回nil
我试图这样实现:
- (APDUResponse *)sendCommandAndWaitForResponse:(NSData *)request {
APDUResponse * result;
if (!deviceIsBusy && request != Nil) {
deviceIsBusy = YES;
timedOut = NO;
responseReceived = NO;
if ([[mySes outputStream] hasSpaceAvailable]) {
[NSThread detachNewThreadSelector:@selector(startTimeout) toTarget:self withObject:nil];
[[mySes outputStream] write:[request bytes] maxLength:[request length]];
while (!timedOut && !responseReceived) {
sleep(2);
NSLog(@"tick");
}
if (responseReceived && response !=nil) {
result = response;
response = nil;
}
[myTimer invalidate];
myTimer = nil;
}
}
deviceIsBusy = NO;
return result;
}
- (void) startTimeout {
NSLog(@"start Timeout");
myTimer = [NSTimer timerWithTimeInterval:10.0 target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];
}
- (void)timerFireMethod:(NSTimer *)timer {
NSLog(@"fired");
timedOut = YES;
}
- (void)stream:(NSStream*)stream handleEvent:(NSStreamEvent)streamEvent
{
switch (streamEvent)
{
case NSStreamEventHasBytesAvailable:
// Process the incoming stream data.
if(stream == [mySes inputStream])
{
uint8_t buf[1024];
unsigned int len = 0;
len = [[mySes inputStream] read:buf maxLength:1024];
if(len) {
_data = [[NSMutableData alloc] init];
[_data appendBytes:(const void *)buf length:len];
NSLog(@"Response: %@", [_data description]);
response = [[APDUResponse alloc] initWithData:_data];
responseReceived = YES;
} else {
NSLog(@"no buffer!");
}
}
break;
... //code not relevant
}
}
最佳答案
而是对固有的异步问题强加不合适的同步方法,而应使方法sendCommandAndWaitForResponse
异步。
可以将“流写入”任务包装到异步操作/任务/方法中。例如,您可以使用以下接口(interface)以NSOperation
的并发子类结尾:
typedef void (^DataToStreamCopier_completion_t)(id result);
@interface DataToStreamCopier : NSOperation
- (id) initWithData:(NSData*)sourceData
destinationStream:(NSOutputStream*)destinationStream
completion:(DataToStreamCopier_completion_t)completionHandler;
@property (nonatomic) NSThread* workerThread;
@property (nonatomic, copy) NSString* runLoopMode;
@property (atomic, readonly) long long totalBytesCopied;
// NSOperation
- (void) start;
- (void) cancel;
@property (nonatomic, readonly) BOOL isCancelled;
@property (nonatomic, readonly) BOOL isExecuting;
@property (nonatomic, readonly) BOOL isFinished;
@end
cancel
方法实现“超时”功能。
sendCommandAndWaitForResponse:
与完成处理程序变为异步:
- (void)sendCommand:(NSData *)request
completion:(DataToStreamCopier_completion_t)completionHandler
{
DataToStreamCopier* op = [DataToStreamCopier initWithData:request
destinationStream:self.outputStream
completion:completionHandler];
[op start];
// setup timeout with block: ^{ [op cancel]; }
...
}
[self sendCommand:request completion:^(id result) {
if ([result isKindOfClass[NSError error]]) {
NSLog(@"Error: %@", error);
}
else {
// execute on a certain execution context (main thread) if required:
dispatch_async(dispatch_get_main_queue(), ^{
APDUResponse* response = result;
...
});
}
}];
NSOperation
子类并不是那么简单。将会出现细微的并发问题,迫使您使用同步原语,例如锁或调度队列,以及一些其他技巧,以使其真正可靠。
NSOperation
子类中,基本上需要相同的“样板”代码。因此,一旦有了通用解决方案,编码工作就是从"template"进行复制/粘贴,然后为特定目的定制代码。
NSOperation
,则甚至不需要
NSOperationQueue
的子类。并发操作可以简单地通过向其发送
start
方法开始-不需要
NSOperationQueue
。然后,不使用
NSOperation
的子类可以使您自己的实现更简单,因为子类
NSOperation
本身具有其自身的微妙之处。
NSStream
对象,因为实现需要保持状态,而这是无法通过简单的异步方法完成的。
start
和
cancel
方法,并具有在基础任务完成时通知调用站点的机制。
@interface WriteDataToStreamOperation : AsyncOperation
- (void) start;
- (void) cancel;
@property (nonatomic, readonly) BOOL isCancelled;
@property (nonatomic, readonly) BOOL isExecuting;
@property (nonatomic, readonly) BOOL isFinished;
@property (nonatomic, readonly) Promise* promise;
@end
sendCommand
方法变为:
- (Promise*) sendCommand:(NSData *)command {
WriteDataToStreamOperation* op =
[[WriteDataToStreamOperation alloc] initWithData:command
outputStream:self.outputStream];
[op start];
Promise* promise = op.promise;
[promise setTimeout:100]; // time out after 100 seconds
return promise;
}
[self sendCommand:request].then(^id(APDUResponse* response) {
// do something with the response
...
return ...; // returns the result of the handler
},
^id(NSError*error) {
// A Stream error or a timeout error
NSLog(@"Error: %@", error);
return nil; // returns nothing
});
sendCommand:
方法中设置超时。
Promise* promise = [self sendCommand:request];
[promise setTimeout:100];
promise.then(^id(APDUResponse* response) {
// do something with the response
...
return ...; // returns the result of the handler
},
^id(NSError*error) {
// A Stream error or a timeout error
NSLog(@"Error: %@", error);
return nil; // returns nothing
});
runLoopWait
方法,通过RXPromise库轻松完成此操作,该方法有效地进入运行循环,并在该循环中等待可解决的 promise :
-(void) testSendingCommandShouldReturnResponseBeforeTimeout10 {
Promise* promise = [self sendCommand:request];
[promise setTimeout:10];
[promise.then(^id(APDUResponse* response) {
// do something with the response
XCTAssertNotNil(response);
return ...; // returns the result of the handler
},
^id(NSError*error) {
// A Stream error or a timeout error
XCTestFail(@"failed with error: %@", error);
return nil; // returns nothing
}) runLoopWait]; // "wait" on the run loop
}
runLoopWait
将进入运行循环,并等待超时或由于基础任务解决了 promise 而导致的 promise 被解决。 Promise不会阻塞主线程,也不会轮询运行循环。解决 promise 后,它将仅离开运行循环。其他运行循环事件将照常处理。
testSendingCommandShouldReturnResponseBeforeTimeout10
而不阻塞它。这是绝对必要的,因为您的Stream委托(delegate)方法也可以在主线程上执行!
关于ios - 如何实现超时/等待NSStream有效地使方法同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20700326/
我收到未知数据,我想以编程方式查看相关性,并将所有完全相关的变量组合在一起(忽略方向)。在下面的数据集中,我可以手动查看相关性并说 a, f, g, h一起去吧b, d, e .我怎样才能以编程方
这个问题在这里已经有了答案: use dplyr's summarise_each to return one row per function? (3 个答案) 关闭 4 年前。 作为探索性工作的
我想要完成的是使用数组存储未知大小的多项式。我在互联网上看到的是使用一个数组,每个单元格都包含系数,度数是单元格编号,但这不是有效的,因为如果我们有一个多项式,如:6x^14+x+5。这意味着我们将从
嘿伙计们,我一直在尝试解析 HTML 文件以从中抓取文本,但时不时地,我会得到一些非常奇怪的字符,例如 à€œ。我确定是“智能引号”或弯头标点符号导致了我的所有问题,因此我的临时修复是搜索所有这些字符
我原来的 data.table 由三列组成。 site、observation_number 和 id。 例如以下是 id = z 的所有观察结果 |site|observation_number|i
"Premature optimisation is the root of all evil (but it's nice to have once you have an ugly solutio
给定这个数组 X: [1 2 3 2 3 1 4 5 7 1] 和行长度数组R: [3 2 5] 表示转换后每行的长度。 我正在寻找一个计算效率高的函数来将 X reshape 为数组 Y: [[ 1
我有一些 data.frame s: # Sample data a <- data.frame(c(1:10), c(11:20)) names(a) <- c("A", "B") b <- dat
我有点困惑。列表擅长任意位置插入,但不善于随机访问? (怎么可能)如果你不能随机访问,你怎么知道在哪里插入? 同样,如果你可以在任何位置插入,为什么你不能从那个位置高效地读取? 最佳答案 如果您已经有
我有一个向量,我想计算它的移动平均值(使用宽度为 5 的窗口)。 例如,如果有问题的向量是[1,2,3,4,5,6,7,8],那么 结果向量的第一个条目应该是 [1,2,3,4,5] 中所有条目的总和
有一个随机整数生成器,它生成随机整数并在后台运行。需求设计一个API,调用时返回当时的簇数。 簇:簇是连续整数的字典顺序。例如,在这种情况下,10,7,1,2,8,5,9 簇是 3 (1,2--5--
我想做的是将一组 (n) 项分成大小相等的组(大小为 m 的组,并且为简单起见,假设没有剩余,即 n 可以被 m 整除)。这样做多次,我想确保同一组中的任何项目都不会出现两次。 为了使这稍微更具体一些
假设我有一些包含类型排列的模板表达式,在本例中它们来自 Abstract Syntax Tree : template
我已经在这方面工作了几天,似乎没有我需要的答案。 由于担心这个被标记为重复,我将解释为什么其他问题对我不起作用。 使用 DIFFLIB for Python 的任何答案都无助于我的需求。 (我在下面描
我正在使用 NumPy 数组。 我有一个 2N 长度向量 D,并希望将其一部分 reshape 为 N x N 数组 C. 现在这段代码可以满足我的要求,但对于较大的 N 来说是一个瓶颈: ``` i
我有一个问题: 让我们考虑这样的 pandas 数据框: Width Height Bitmap 67 56 59 71 61 73 ...
我目前正在用 C 语言编写一个解析器,设计它时我需要的东西之一是一个可变字符串“类”(一组对表示实例的不透明结构进行操作的函数),我将其称为 my_string。 string 类的实例只不过是包装
假设我在 --pandas-- 数据框中有以下列: x 1 589 2 354 3 692 4 474 5 739 6 731 7 259 8 723
我有一个成员函数,它接受另一个对象的常量引用参数。我想 const_cast 这个参数以便在成员函数中轻松使用它。为此,以下哪个代码更好?: void AClass::AMember(const BC
我们目前正在将 Guava 用于其不可变集合,但我惊讶地发现他们的 map 没有方法可以轻松创建只需稍作修改的新 map 。最重要的是,他们的构建器不允许为键分配新值或删除键。 因此,如果我只想修改一
我是一名优秀的程序员,十分优秀!