0

これが私が使用しているコードのスニペットです。というモデルがありx_locatorます。モデルをマルチスレッド化すると、maps.google.com は 620 エラーを返します (要求が多すぎて速すぎます) が、モデルをメイン スレッドに残すと問題なく動作します...要求が行われている間は UI だけがロックされます.

-(CLLocationCoordinate2D) getLocationFromAddressString:(NSString*) addressStr {
    NSString *urlStr = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?    q=%@&output=csv", 
                       [addressStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    NSString *locationStr = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlStr]];
    NSArray *items = [locationStr componentsSeparatedByString:@","];

    double lat = 0.0;
    double lon = 0.0;

    if([items count] >= 4 && [[items objectAtIndex:0] isEqualToString:@"200"]) {
        lat = [[items objectAtIndex:2] doubleValue];
        lon = [[items objectAtIndex:3] doubleValue];
    }
    else {
        NSLog(@"Address, %@ not found: Error %@",addressStr, [items objectAtIndex:0]);
    }
    CLLocationCoordinate2D location;
    location.latitude = lat;
    location.longitude = lon;

    return location;
}

編集:これが私がGCDを使用しようとした方法です...これは私のViewControllerにあります

- (void)viewDidLoad
{
    [super viewDidLoad];

    //set any delegates
    self.locationManager.delegate = self;
    [locationManager startUpdatingLocation];
    fuelMapView.showsUserLocation = YES;

    [self setInitialRegion];
    locationManager.distanceFilter = 100;

    //create the model
    x_locator = [[Locator alloc]init];
    x_locator.delegate = self;

    dispatch_queue_t finder = dispatch_queue_create("Locator", NULL);
    //if I do this, only some of the locations are found. If I leave it on the main thread, all locations are found.
    dispatch_async(finder, ^{
    [x_locator getUsersZipUsingLocation:[locationManager location]];
     });
}

リバース ジオコーディングを使用してユーザーの郵便番号を取得し、(ユーザーの郵便番号に従って) 住所の配列を取得する別のメソッドを呼び出し、最後にこれらgetUsersZipUsingLocation:の住所のそれぞれを次を使用して座標位置に変換するだけです。-(CLLocationCoordinate2D) getLocationFromAddressString:(NSString*) addressStr

編集2:人々が質問の焦点を失い、私のコーディングの優雅さを判断する可能性があるため、コード全体を投稿することを非常にためらっています....

とにかく...メソッドを呼び出す前に-(CLLocationCoordinate2D) getLocationFromAddressString:(NSString*) addressStr、変数として渡すことができる形式にアドレスを組み立てる必要がありますaddressStr。アドレスはバラバラに届くので、バラバラに組み立ててから、URLからデータを取得します...

NSString *urlStr = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv",
                    [addressStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

データが返されたら、私が言う[NSThread sleepForTimeInterval:0.05];と、次のリクエストが実行されます。

私はあなたのコメントと時間に感謝します:)

4

1 に答える 1

2

まず、getLocationFromAddressString:接頭辞を付けないでくださいget。試しdownloadたりretrieve、省略したりしてください(慣例)。

次に、実際にどのように呼び出しを同時に行っているかについての詳細を投稿してください。いくつのリクエストをしていますか?

「リクエストが多すぎて速すぎる」というのは、かなり正確に聞こえます。リモートサーバーでリクエストを投げる速度を調整する必要があります。

私は過去にセマフォを使用して並行性を抑制しました。

複数のファイルを開くためのグランドセントラル戦略


すべての getUsersZipUsingLocation: は、リバース ジオコーディングを使用してユーザーの郵便番号を取得し、(ユーザーの郵便番号に従って) 住所の配列を取得する別のメソッドを呼び出し、最後に -(CLLocationCoordinate2D) を使用してそれらの住所のそれぞれを座標位置に変換します。 getLocationFromAddressString:(NSString*) addressStr

呼び出される場所:

dispatch_async(finder, ^{
[x_locator getUsersZipUsingLocation:[locationManager location]];
 });

まず、その情報をロードするための非同期呼び出しができました。したがって、アイテムの「一部」しか見つからないことは驚くことではありません。非同期に移行したらすぐに、なんらかの通知メカニズムを使用して、ロードがいつ完了したかを示す必要があります

それが同期であると仮定するとusersZipUsingLocation:、次のことができます。

dispatch_async(finder, ^{
[x_locator getUsersZipUsingLocation:[locationManager location]];
[self yoManILoadedTheGoodsDealWithTheUpdate];
 });

しかし、それでも 620 を説明することはできません。その 620 は、多数のリクエストを同時に (またはほとんど) 送信していることを示しています。上記のいずれにも、主張されている 50 ミリ秒の遅延はありません。

というわけで... この話にはまだ続きがあるようです! :)


API リクエストの制限に達している理由はまだ明確ではありません。

この種のことを遅らせるためにスリープメカニズムを使用するべきではありません。代わりに、絶対に必要な場合は、セマフォのようなパターンを組み合わせて使用​​し、(できればシステムの非同期読み込み API を使用して) 同時進行中のリクエストの数を制御し、タイマー ベースの遅延と組み合わせます。これにより、保証されたスレッド コントラクトなしで、すべての遅延関連の要素がシステムにプッシュされます (スレッドのスリープに必要な場合)。

于 2013-01-22T00:29:41.777 に答える