-2

假设我有几个地址。我需要获取循环中每个地址的坐标。但是获取一个地址的坐标需要一些时间。如何在一个周期内异步获取坐标?

4

1 回答 1

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
于 2013-01-13T13:44:07.317 回答