2012-04-24 61 views
2
.h 
@property (strong) NSString *reply; 

我有以下方法:NSURL连接sendAsynchronousRequest如何保存响应?

.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]]; 
          } 
         }]; 

} 

现在,我试图从块/处理程序返回一个值,但显然这是不可能的(或者我还没有想出的语法还)。

我试图设置一个局部变量来获得答复(数据)的值,但它会产生错误。

错误没有产生的唯一方法是使用类属性。但是当我试图读取[自我回复]的价值时,它是空的,这使我认为它从未设置。

据我所知,sendAsync函数是线程和异步的,所以是[自我答复]的值为空的原因,而当我使用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

我不明白的问题/问题。为什么不能从块完成功能返回一个值? setReply函数有什么作用?向我们显示代码 – Lefteris 2012-04-24 15:10:21

+0

设置断点以查看数据是否有效或为空。 你在正确的轨道上,这似乎有效,但你可能没有得到可以使用的信息。 – 2012-04-24 15:28:21

+0

该块被指定为具有void返回类型,所以块本身不能返回值 - 但为什么需要返回值?我猜你的setReply函数只是一个实例变量的setter?在这种情况下,您不需要从块中返回任何内容,因为当您设置回复时将会捕获响应。使用本地变量捕获数据值时产生的错误是什么?你应该能够设置一个断点来查看数据。另外,我会添加检查您收到的响应代码。 – tronbabylove 2012-04-24 15:29:06

回答

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)。 但它现在异步工作,不冻结用户界面,并具有适当的错误报告。 希望它可以帮助有人卡住在同一问题

+1

如果你投了票 - 至少花时间说出原因 – 2014-10-03 23:04:56

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]; 
+0

试过了,没有什么区别。我的猜测是主线程终止比异步发送操作更快结束。谢谢你告诉我这个,它很好理解。 – 2012-04-25 09:54:31

+1

那么如果你正在使用这个异步调用,并且你希望主线程等待响应,你必须阻塞主线程。我在用SenTestCase编写测试时遇到了这个问题。看看我用来阻塞主线程的方法。 – bas 2012-04-25 12:31:21

+0

非常感谢您花时间回复并添加了代码。不幸的是,我得不到它建立,因为我得到一个错误的类型的参数传递给块函数(从无符号字符BOOL无效块指针转换为(布尔)^())。更重要的是,在我看来,我们正在以同样的方式采用不同的方法。我在主队列中添加了异步发送,然后告诉它运行10秒(我的超时)。是不是你在做什么,除了你所做的一切将会阻止一旦返回值的阻塞? – 2012-04-26 09:34:19

2

摆脱runUntilDate,并尝试使用[NSOperationQueue mainQueue],看看有没有什么变化anythi NG。

[NSURLConnection sendAsynchronousRequest:[self request] 
      queue:[NSOperationQueue mainQueue] 
      completionHandler: 
        ^(NSURLResponse *response, NSData *data, NSError *error)...  
+0

我试过了,没有什么区别。这实际上是我第一次尝试它的方式。 – 2012-04-25 09:50:01