2013-01-13 77 views
-2

假設我有幾個地址。我需要獲取循環中每個地址的座標。但獲取一個地址的座標需要一些時間。如何在一個循環中異步獲取座標?ios CLGeocoder。異步地理編碼

+0

的 「怎麼辦」 的問題的數量有所增加。如果你還沒有找到任何你仍然可以問的問題,但請至少在網上搜索。 –

回答

5

您可以編寫一個例程,對可變數組中的單個地址進行地理編碼,然後調用自身來處理完成塊中的下一個地址。因此:

- (void)nextGeocodeRequest { 
    // if we're done, dp whatever you want 

    if ([self.addresses count] == 0) { 
     // do whatever you want when we're done (e.g. open maps) 

     return; 
    } 

    // if not, get the next address to geocode from NSMutableArray and 
    // remove it from list of addresses to process 

    NSString *address = self.addresses[0]; 
    [self.addresses removeObjectAtIndex:0]; 

    // geocode the address 

    CLGeocoder *geocoder = [[CLGeocoder alloc]init]; 

    [geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) { 

     // do whatever you want for the individual geocode process 

     // when all done, queue up the next geocode address 

     [self nextGeocodeRequest]; 
    }]; 
} 

或者,更復雜,你可以使用操作隊列:

- (void)geocodeAddresses:(NSArray <NSString *>*)addresses { 
    CLGeocoder *geocoder = [[CLGeocoder alloc]init]; 

    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
    queue.maxConcurrentOperationCount = 1; 
    queue.name = @"com.domain.app.geocode"; 

    NSOperation *finalCompletionOperation = [NSBlockOperation blockOperationWithBlock:^{ 
     // do whatever you want when all done 
     NSLog(@"done"); 
    }]; 

    for (NSString *address in addresses) { 
     // create a block for the geocode request completion block 

     NSOperation *geocodeOperation = [[GeocodeOperation alloc] initWithGeocoder:geocoder Address:address geocodeCompletionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { 
      if (error) { 
       NSLog(@"error = %@", error); 
      } else { 
       NSLog(@"placemarks = %@", placemarks); 
      } 
     }]; 

     // The final completion block is contingent on the completion of this geocode request completion block 

     [finalCompletionOperation addDependency:geocodeOperation]; 

     // let's queue the geocode request 

     [queue addOperation:geocodeOperation]; 
    } 

    [queue addOperation:finalCompletionOperation]; 
} 

其中,GeocodeOperation.h

#import "AsynchronousOperation.h" 
@import CoreLocation; 

NS_ASSUME_NONNULL_BEGIN 

@interface GeocodeOperation : AsynchronousOperation 

@property (readonly, nonatomic, copy) NSString *address; 

- (instancetype)initWithGeocoder:(CLGeocoder *)geocoder Address:(NSString *)address geocodeCompletionHandler:(CLGeocodeCompletionHandler) geocodeCompletionHandler; 

@end 

NS_ASSUME_NONNULL_END 

而且,GeocodeOperation.m

#import "GeocodeOperation.h" 

@interface GeocodeOperation() 
@property (nonatomic, strong) CLGeocoder *geocoder; 
@property (nonatomic, copy, nonnull) NSString *address; 
@property (nonatomic, copy) CLGeocodeCompletionHandler geocodeCompletionHandler; 
@end 

@implementation GeocodeOperation 

- (instancetype)initWithGeocoder:(CLGeocoder *)geocoder Address:(NSString * _Nonnull)address geocodeCompletionHandler:(CLGeocodeCompletionHandler) geocodeCompletionHandler { 
    self = [super init]; 
    if (self) { 
     self.geocoder = geocoder; 
     self.address = address; 
     self.geocodeCompletionHandler = geocodeCompletionHandler; 
    } 
    return self; 
} 

- (void)main { 
    [self.geocoder geocodeAddressString:self.address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { 
     self.geocodeCompletionHandler(placemarks, error); 
     [self completeOperation]; 
    }]; 
} 

- (void)cancel { 
    [self.geocoder cancelGeocode]; 
    [super cancel]; 
} 

@end 

AsynchronousOperation.h

@interface AsynchronousOperation : NSOperation 

/// Complete the asynchronous operation. 
/// 
/// This also triggers the necessary KVO to support asynchronous operations. 

- (void)completeOperation; 

@end 

而且AsynchronousOperation.m

// 
// AsynchronousOperation.m 
// 

#import "AsynchronousOperation.h" 

@interface AsynchronousOperation() 

@property (getter = isFinished, readwrite) BOOL finished; 
@property (getter = isExecuting, readwrite) BOOL executing; 

@end 

@implementation AsynchronousOperation 

@synthesize finished = _finished; 
@synthesize executing = _executing; 

- (instancetype)init { 
    self = [super init]; 
    if (self) { 
     _finished = NO; 
     _executing = NO; 
    } 
    return self; 
} 

- (void)start { 
    if (self.isCancelled) { 
     if (!self.isFinished) self.finished = YES; 
     return; 
    } 

    self.executing = YES; 

    [self main]; 
} 

- (void)completeOperation { 
    if (self.isExecuting) self.executing = NO; 
    if (!self.isFinished) self.finished = YES; 
} 

#pragma mark - NSOperation methods 

- (BOOL)isAsynchronous { 
    return YES; 
} 

- (BOOL)isExecuting { 
    @synchronized(self) { return _executing; } 
} 

- (BOOL)isFinished { 
    @synchronized(self) { return _finished; } 
} 

- (void)setExecuting:(BOOL)executing { 
    [self willChangeValueForKey:@"isExecuting"]; 
    @synchronized(self) { _executing = executing; } 
    [self didChangeValueForKey:@"isExecuting"]; 
} 

- (void)setFinished:(BOOL)finished { 
    [self willChangeValueForKey:@"isFinished"]; 
    @synchronized(self) { _finished = finished; } 
    [self didChangeValueForKey:@"isFinished"]; 
} 

@end 
+0

awsome!拯救了我的一天! – SwingerDinger

+1

@SingerDinger - 我不知道你是使用我的第一個例子還是我的第二個例子,但第二個例子並不是很正確,但我已經修復它以使用正確的異步操作。 – Rob

+0

我已經使用過你的第二個實現並將其轉換成Swift 3.0。像魅力一樣工作。 – SwingerDinger

相關問題