Renvoie NSSsortingng qui est défini à l'intérieur d'un bloc

J'ai une méthode qui ressemble à ceci:

-(NSSsortingng *)getCityFromLocation:(CLLocation *)location { __block NSSsortingng *city; CLGeocoder *geocoder = [[CLGeocoder alloc] init]; [geocoder reverseGeocodeLocation: location completionHandler: ^(NSArray *placemarks, NSError *error) { //Get address CLPlacemark *placemark = [placemarks objectAtIndex:0]; city = [placemark.addressDictionary objectForKey:@"City"]; NSLog(@"city 1: %@", city); }]; return city; } 

Et je l'appelle comme ceci:

 NSSsortingng *city = [self getCityFromLocation:currentLocation]; NSLog(@"city 2: %@", city); 

Dans NSLog, j'obtiens:

 city 2: (null) city 1: London 

Le problème est évident: il revient avant que le bloc ne soit lancé. Comment puis-je faire en sorte que cela fonctionne comme prévu, où il peut returnner la valeur produite par le bloc?

Initialement, vous avez asssign achèvement block à reverseGeocodeLocation . Mais il n'appelle pas à ce moment-là. Il appellera lorsque le reverse Geocode process get complete . Mais la city reviendra immédiatement. Voilà pourquoi vous obtenez comme ça.

Vous pouvez résoudre en l'assignant à la propriété locale. Lorsque le bloc d'achèvement est exécuté. Donc, le code devrait être.

 [geocoder reverseGeocodeLocation: location completionHandler: ^(NSArray *placemarks, NSError *error) { //Get address CLPlacemark *placemark = [placemarks objectAtIndex:0]; self.city = [placemark.addressDictionary objectForKey:@"City"]; }]; 

Au lieu de créer un bloc à l'intérieur de getCityFromLocation , transformez getCityFromLocation en bloc (je veux dire methods de callback).

 typedef void (^Callback)(BOOL isSuccess, id object); -(void)getCityFromLocation:(Callback)iCallback { CLGeocoder *geocoder = [[CLGeocoder alloc] init]; [geocoder reverseGeocodeLocation: location completionHandler: ^(NSArray *placemarks, NSError *error) { //Get address CLPlacemark *placemark = [placemarks objectAtIndex:0]; city = [placemark.addressDictionary objectForKey:@"City"]; NSLog(@"city 1: %@", city); iCallback(YES,city); }]; } 

Les methods asynchronouss, telles que reverseGeocodeLocation: vous avez utilisé ici, sont normalement utilisées pour une très bonne raison – elles prennent du time à compléter. Dans cette optique, vous devriez d'abord considérer votre design et déterminer si vous devriez vraiment essayer d'utiliser une méthode asynchronous de manière synchrone.

Si vous décidez que vous devez faire cela, une solution consiste à utiliser un sémaphore. Avant l'appel de reverseGeocodeLocation: créez un sémaphore avec dispatch_semaphore_create (partie de GCD, dans la section 3 du manuel). Ensuite, dans votre bloc, vous utilisez dispatch_semaphore_signal pour indiquer que la string est prête, et en dehors de votre bloc dispatch_semaphore_wait pour bloquer jusqu'à ce que la string soit prête.

Votre code modifié pour ce faire, tapé directement dans la réponse et non exécuté :

 #include <dispatch/dispatch.h> -(NSSsortingng *)getCityFromLocation:(CLLocation *)location { __block NSSsortingng *city; dispatch_semaphore_t sema = dispatch_semaphore_create(0); CLGeocoder *geocoder = [[CLGeocoder alloc] init]; [geocoder reverseGeocodeLocation: location completionHandler: ^(NSArray *placemarks, NSError *error) { //Get address CLPlacemark *placemark = [placemarks objectAtIndex:0]; city = [placemark.addressDictionary objectForKey:@"City"]; dispatch_semaphore_signal(sema); // ssortingng is ready } ]; dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); // wait for ssortingng dispatch_release(sema); // if you are using ARC & 10.8 this is NOT needed return city; } 

Mais sérieusement, réfléchissez bien pour savoir si c'est ce que vous devriez faire.

HTH.