NSURL Connection sendAsynchronousRequest如何保存响应?

时间:2012-04-24 15:06:56

标签: ios objective-c xcode nsurlconnection completionhandler

.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运行时,它会一直阻塞所有内容,就像当前线程永远不会终止一样。

3 个答案:

答案 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];