.h
@property (strong) NSString *reply;
我有以下方法:
.m
@synthesize reply;
- (void)send
{
[NSURLConnection sendAsynchronousRequest:[self request]
queue:[[NSOperationQueue alloc] init]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error)
{
if (error)
{
//NSLog(@"Error,%@", [error localizedDescription]);
[self setReply: [[NSString alloc] initWithString:[error localizedDescription]]];
}
else
{
//NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
[self setReply: [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]];
}
}];
}
现在,我试图从块/处理程序返回一个值,但显然这是不可能的(或者我还没有弄清楚语法)。
我试图设置一个局部变量来获取回复(Data)的值,但它会产生错误。
不产生错误的唯一方法是使用类属性。但是当我尝试读取[self reply]的值时,它为null,这让我觉得它永远不会被设置。
据我所知,sendAsync函数是线程化和异步的,因此[self reply]的值为null的原因是,当我使用sendSynchronousRequest时,我总是得到一个回复???
我做错了什么,如何从completionHandler ???
中返回一个值编辑#1:在我看来,我做的事情非常错误。我正在追踪代码,当我使用同步发送时,一切正常。使用异步调用,从未执行对sendAsynchronousRequest的实际调用,这使我认为线程没有被调用,因此是空值。
编辑#2:通过添加以下内容,我找到了解决方法:
[NSURLConnection sendAsynchronousRequest:[self request]
queue:[NSOperationQueue alloc] init
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error)
{
if (error)
{
//NSLog(@"Error,%@", [error localizedDescription]);
[self setReply: [[NSString alloc] initWithString:[error localizedDescription]]];
}
else
{
//NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
[self setReply: [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]];
}
}];
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 2]];
然而,我并不完全确定我理解它是如何运作的。我想RunLoop告诉异步操作运行2秒(我可以验证,因为当将日期间隔设置为较低值时,由于使用实时服务器测试,我得到空响应)。我不明白的是,当我告诉RunLoop运行时,它会一直阻塞所有内容,就像当前线程永远不会终止一样。
答案 0 :(得分:2)
摆脱runUntilDate并尝试使用[NSOperationQueue mainQueue],看看是否有任何改变。
[NSURLConnection sendAsynchronousRequest:[self request]
queue:[NSOperationQueue mainQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error)...
答案 1 :(得分:2)
差不多一个月后,我找到了解决问题的方法:
NSURLConnection* _connection = [[NSURLConnection alloc] initWithRequest:[self request] delegate:self startImmediately:NO];
self.port = [NSPort port];
self.runloop = [NSRunLoop currentRunLoop];
[self.runloop addPort:self.port forMode:NSDefaultRunLoopMode];
[_connection scheduleInRunLoop:self.runloop forMode:NSDefaultRunLoopMode];
[_connection start];
while (self.finished != YES ) {
[self.runloop runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 0.1]];
}
[self.runloop removePort:[self port] forMode:NSDefaultRunLoopMode];
[_connection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
这对我有用。请记住,我必须正确实现NSConnection的委托方法(didReceiveResponse,didReceiveData,didFailWithError,connectionDidFinishLoading)。 但是它现在异步工作,不会冻结UI,并且具有正确的错误报告。 希望它可以帮助有人坚持同样的问题
答案 2 :(得分:0)
您应该尝试使用__block关键字来声明您的属性回复
@property (strong) __block NSString *reply;
此关键字使您的属性可以在块内写入。
修改强>
建议阻止主线程直到收到响应或请求超时之前的方法:
//this block is used to define a waiting condition
typedef BOOL (^ CheckBlock)();
- (BOOL)waitUntilBlockTrue:(CheckBlock)theBlock orTimeout:(int)timeout {
NSDate *waitingStartPoint = [NSDate date];
BOOL stillNeedToWait = YES;
while (stillNeedToWait && theBlock()) {
stillNeedToWait = ([waitingStartPoint timeIntervalSinceNow]*(-1.0)) < timeout;
}
return stillNeedToWait;
}
对于您的示例,您可以使用以下方法调用此方法:
[self waitUntilBlockTrue:^{
//returns YES as long as the method should block
return (BOOL)(self.reply == nil);
} orTimeout:10];