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

}

今、ブロック/ハンドラーから値を返そうとしましたが、明らかにこれは不可能です (または、まだ構文を理解していません)。

応答 (データ) の値を取得するためにローカル変数を設定しようとしましたが、エラーが発生します。

エラーが発生しない唯一の方法は、クラス プロパティを使用することです。しかし、[自己返信] の値を読み込もうとすると 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 秒間実行するように指示していると思います (日付間隔を低い値に設定すると、ライブ サーバーでのテストにより null 応答が返されるため、確認できます)。私が理解していないのは、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

ほぼ 1 か月後、問題の解決策を見つけました。

    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 に答える