3

次の動作を引き起こす特別なプロパティ NSRunLoop を見つけようとしています。

まず、私がやろうとしているのは、先に進む前に CLGeocoder の実行が完了するのを待つことです。完了ブロックを使用すると、コードは次のようになります。

if (/* loc has valid coordinates */)
    [gc reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError error){
        //do things
        [gc reverseGeocodeLocation:newloc completionHandler:^(NSArray *placemarks, NSError error){
            //do more things with newloc
            // MOVE TO NEXT VIEW
        }
     }
else if (/*still have to check for newloc*/)
    [gc reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError error){
        //do things
        //MOVE TO NEXT VIEW

残念ながら、//do thingsこれらのブロックの部分は冗長であり、CLGeocoder を独自の関数にネストし、2 回呼び出した後に次のビューに移動すると、はるかにクリーンになります。

ここでの答えのおかげで強制的に待機する方法を見つけました: Waiting for CLGeocoder to finish on concurrent enumeration

したがって、新しい方法は機能しますが、なぜ機能するのかわかりません。コードは次のとおりです。

dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);

[gc reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError *error){
    //do things
    dispatch_group_leave(group);
}

//this is the confusing part!
while(dispatch_group_wait(group,DISPATCH_TIME_NOW)){
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0f]];
}
dispatch_release(group);

奇妙なことに、while ループを使用せずに次の操作を行うと、アプリがハングします。

dispatch_group_wait(group,DISPATCH_TIME_FOREVER);

私がこれまでに読んだすべてのことを考えると、それはうまくいくはずですよね?


さらに紛らわしいことに、while ループ内では NSRunLoop が必要です。空の while ループを残して完全に削除すると、ループは際限なく繰り返されます。そのようです:

//this is the confusing part!
while(dispatch_group_wait(group,DISPATCH_TIME_NOW)){
    //without NSRunLoop, this just goes on forever
}

while ループを正常に終了させるために NSRunLoop が行っていることは何ですか?

4

1 に答える 1

2

CLGeocoderドキュメントには、メインスレッドで完了ハンドラーブロックを実行すると書かれています。メインスレッドで待機またはwhile(dispatch_group_wait(...))ループを実行していると思います。メイン スレッドをブロックしている場合、メイン スレッドは完了ブロックを実行できません。

while ループを呼び出すことrunMode:beforeDate:で、実行ループに完了ブロックを実行する機会を与えます。

あなたのしていることは悪いことです。メイン スレッドをブロックしてはいけません。また、実行ループを再帰的に実行しないようにする必要があります (ご存じのように、混乱を招くためです)。CLGeocoder完了ブロックを提供できる理由は、完了ブロックを設定してからメインの実行ループに戻ることができるようにするためです。後でCLGeocoder完了ブロックを実行すると、必要な方法で結果を使用できます。

于 2012-10-11T04:50:34.113 に答える