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

}

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

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

不产生错误的唯一方法是使用类属性。但是当我尝试读取 [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 运行时,它会永远阻塞一切,就好像当前线程从未终止一样。

4

3 回答 3

2

摆脱那个 runUntilDate 并尝试使用 [NSOperationQueue mainQueue],看看这是否会改变任何东西。

[NSURLConnection sendAsynchronousRequest:[self request] 
             queue:[NSOperationQueue mainQueue]
             completionHandler:
                    ^(NSURLResponse *response, NSData *data, NSError *error)...     
于 2012-04-24T19:25:14.100 回答
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,并且有适当的错误报告。希望它可以帮助遇到同样问题的人

于 2012-06-01T12:14:44.310 回答
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];
于 2012-04-24T17:15:37.997 回答