xcode NSURL Connection sendAsynchronousRequest 如何保存响应?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10300707/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
NSURL Connection sendAsynchronousRequest How to save the response?
提问by ?lex
.h
@property (strong) NSString *reply;
I have the following method:
我有以下方法:
.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]];
}
}];
}
Now, I have tried to return a value from the block/handler, but apparently this is not possible ( or I haven't figured out the syntax yet ).
现在,我试图从块/处理程序返回一个值,但显然这是不可能的(或者我还没有弄清楚语法)。
I have tried to set a local variable to get the value of the reply (Data) but it produces errors.
我试图设置一个局部变量来获取回复(数据)的值,但它会产生错误。
The only way that errors were not produced is by using a class property. But when I try to read the value of [self reply] it is null, which makes me think that it is never set.
不产生错误的唯一方法是使用类属性。但是当我尝试读取 [self reply] 的值时,它为 null,这让我认为它从未设置过。
I understand that the sendAsync function is threaded and asynchronous, so is that the reason that the value of [self reply] is null, while when I use a sendSynchronousRequest, I always get a reply ???
我知道sendAsync 函数是线程化和异步的,所以是[self reply] 的值为null 的原因,而当我使用sendSynchronousRequest 时,我总是得到回复???
What am I doing wrong, and how can I return a value from within the completionHandler ???
我做错了什么,我怎样才能从 completionHandler 中返回一个值???
Edit#1: It appears to me that Im doing something very wrong. I was tracing into the code, and when I used the synchronous send, everything worked fine. Using the asynchronous one, the actual call to sendAsynchronousRequest was never executed, making me think that the thread is not being invoked, and hence the empty value.
编辑#1:在我看来,我做错了什么。我正在跟踪代码,当我使用同步发送时,一切正常。使用异步的,对 sendAsynchronousRequest 的实际调用从未执行过,让我认为线程没有被调用,因此是空值。
Edit#2: I have found a way around this, by adding the following:
编辑#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]];
However, I am not entirely sure I understand how it works. I imagine that RunLoop tells the async operation to run for 2 seconds ( I can verify because when setting the date interval to a low value, I get a null response, due to testing with a live server ). What I do not understand, is when I just tell the RunLoop to run, it keeps blocking everything forever, as if the current thread never terminated.
但是,我不完全确定我理解它是如何工作的。我想象 RunLoop 告诉异步操作运行 2 秒(我可以验证,因为在将日期间隔设置为低值时,由于使用实时服务器进行测试,我得到空响应)。我不明白的是,当我只是告诉 RunLoop 运行时,它会永远阻塞一切,就好像当前线程从未终止一样。
采纳答案by ?lex
Almost a month later, I found the solution to my problem:
将近一个月后,我找到了解决问题的方法:
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];
This did the trick for me. Bear in mind I had to properly implement NSConnection's delegate methods (didReceiveResponse,didReceiveData,didFailWithError,connectionDidFinishLoading). However it is now working asynchronously, does not freeze the UI, and has proper error reporting. Hope it may help someone stuck at the same issue
这对我有用。请记住,我必须正确实现 NSConnection 的委托方法(didReceiveResponse、didReceiveData、didFailWithError、connectionDidFinishLoading)。但是,它现在异步工作,不会冻结 UI,并且具有正确的错误报告。希望它可以帮助陷入同一问题的人
回答by tronbabylove
Get rid of that runUntilDate and try using [NSOperationQueue mainQueue], see if that changes anything.
摆脱那个 runUntilDate 并尝试使用 [NSOperationQueue mainQueue],看看是否有任何改变。
[NSURLConnection sendAsynchronousRequest:[self request]
queue:[NSOperationQueue mainQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error)...
回答by bas
You should try to use the __block keyword for the declaration of your property reply
您应该尝试使用 __block 关键字来声明您的属性回复
@property (strong) __block NSString *reply;
This keyword makes your property writable from inside a block.
此关键字使您的属性可从块内写入。
EDIT
编辑
Proposal for a method that blocks the main thread until a response is received or until the request times out:
关于阻塞主线程直到收到响应或直到请求超时的方法的建议:
//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;
}
For your example you would call this method with:
对于您的示例,您将使用以下命令调用此方法:
[self waitUntilBlockTrue:^{
//returns YES as long as the method should block
return (BOOL)(self.reply == nil);
} orTimeout:10];