gpt4 book ai didi

ios - 按距离对 UITableView 进行排序

转载 作者:行者123 更新时间:2023-12-01 09:54:39 25 4
gpt4 key购买 nike

我正在尝试按从坐标计算的距离升序对我的表格 View 进行排序。一切都像一个魅力,除了我不能按升序得到它,我一直在捣乱 NSSortDescriptor 等,但不幸的是,任何帮助将不胜感激,这是我的代码:

- (void) retrieveData
{
NSURL *url = [NSURL URLWithString:jsonFile];
NSData *data = [NSData dataWithContentsOfURL:url];

_jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

_salesArray = [[NSMutableArray alloc]init];

for (int i = 0; i < _jsonArray.count; i++) {

NSString *sID = [[_jsonArray objectAtIndex:i] objectForKey:@"id"];
NSString *sName = [[_jsonArray objectAtIndex:i] objectForKey:@"name"];
NSString *sAddress = [[_jsonArray objectAtIndex:i] objectForKey:@"address"];
NSString *sPostcode = [[_jsonArray objectAtIndex:i] objectForKey:@"postcode"];


__block NSString *distance;
CLGeocoder *geocoder = [[CLGeocoder alloc]init];
[geocoder geocodeAddressString:sPostcode completionHandler:^(NSArray *placemarks, NSError *error) {


if (error == nil && placemarks.count > 0) {

CLPlacemark *placemark = [placemarks objectAtIndex:0];


CLLocation *location = placemark.location;
CLLocation *myLocation = self.manager.location;
CLLocationDistance miles = [location distanceFromLocation:myLocation];
//this is the variable i want in my convenience init.
distance = [NSString stringWithFormat:@"%.1f m", (miles/1609.344)];
}
}];

[_salesArray addObject:[[sales alloc] initWithSales:sID andName:sName andAddress:sAddress andPostcode:distance]];

}

[_salesArray sortUsingComparator:
^NSComparisonResult(id obj1, id obj2){
sales *p1 = (sales *)obj1;
sales *p2 = (sales *)obj2;
if (p1.postcode > p2.postcode) {
return (NSComparisonResult)NSOrderedDescending;
}

if (p1.postcode < p2.postcode) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}
];

[self.tableView reloadData];
}

最佳答案

这里有几个问题:

  1. geocodeAddressString 施加了一些限制,如文档中所述:

    This method submits the specified location data to the geocoding server asynchronously and returns. Your completion handler block will be executed on the main thread. After initiating a forward-geocoding request, do not attempt to initiate another forward- or reverse-geocoding request.

    Geocoding requests are rate-limited for each app, so making too many requests in a short period of time may cause some of the requests to fail. When the maximum rate is exceeded, the geocoder passes an error object with the value kCLErrorNetwork to your completion handler.

    这里的几个关键观察结果:

    • 这是异步运行的(因此您不能调用 geocodeAddressString 并在之后立即使用其结果)。您确实调用了完成 block 内部的地理编码工作。

    • 在上一个地理编码请求完成之前,您不应该开始下一个地理编码请求。

    这意味着您必须对第一个邮政编码进行地理编码,让它异步完成(即稍后),对下一个邮政编码进行地理编码,让它完成,等等,然后才进行排序并重新加载表格。简单的 for 循环不是执行此操作的合适方法。您可以编写一个方法来执行单个地理编码并在完成 block 中调用下一个地理编码,或者您可以使用 NSOperation 子类,如下所示。

  2. 我建议将距离 存储为NSNumber。在 MVC 中,小数点后一位字符串表示是一种“ View ”行为,可能不应该是“模型”的一部分。

    这样做的好处是,当你想对对象进行排序时,你可以简单地调用 NSNumbercompare 方法。例如,如果 salesPersonnel 是一个 NSMutableArray 对象,每个 SalesPerson 对象都有一个名为 NSNumber 属性distance,然后你可以这样做:

    [self.salesPersonnel sortUsingComparator:^NSComparisonResult(SalesPerson *obj1, SalesPerson *obj2) {
    return [obj1.distance compare:obj2.distance];
    }];

    我不确定您的 sales 条目是否针对实际销售交易或销售人员,所以如果我误解了对象类型,我深表歉意,但希望这能说明这个想法。

    <

您可以按照自己的方式执行此操作,但对我来说,当我想运行多个异步任务但按顺序执行时,我倾向于并发 NSOperation 子类,我将添加该子类到串行 NSOperationQueue

NSError *error;
NSArray *addressEntries = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSAssert(addressEntries, @"unable to parse: %@", error);

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;

self.salesPersonnel = [NSMutableArray array];

// define sort operation that will be called when all of the geocode attempts are done

NSOperation *sortAndReloadTableOperation = [NSBlockOperation blockOperationWithBlock:^{
[self.salesPersonnel sortUsingComparator:^NSComparisonResult(SalesPerson *obj1, SalesPerson *obj2) {
return [obj1.distance compare:obj2.distance];
}];

[self.tableView reloadData];
}];

// create the geocode operations

for (NSDictionary *addressEntry in addressEntries) {
SalesPerson *salesPerson = [[SalesPerson alloc] initWithSalesId:addressEntry[@"id"]
name:addressEntry[@"name"]
address:addressEntry[@"address"]
postalCode:addressEntry[@"postcode"]];
[self.salesPersonnel addObject:salesPerson];

NSOperation *geocodeOperation = [[GeocodeOperation alloc] initWithPostalCode:salesPerson.postalCode completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks firstObject];

CLLocation *location = placemark.location;
CLLocationDistance meters = [location distanceFromLocation:self.currentLocation];
salesPerson.distance = @(meters / 1609.344);
}];

[sortAndReloadTableOperation addDependency:geocodeOperation]; // note, the final sort is dependent upon this finishing

[queue addOperation:geocodeOperation]; // go ahead and queue up the operation
}

// now we can queue the sort and reload operation, which won't start until the geocode operations are done

[[NSOperationQueue mainQueue] addOperation:sortAndReloadTableOperation];

GeocodeOperation 是一个基本的并发 NSOperation 子类:

//  GeocodeOperation.h

#import <Foundation/Foundation.h>

typedef void(^GeocodeCompletionHandler)(NSArray *placemarks, NSError *error);

@interface GeocodeOperation : NSOperation

@property (nonatomic, copy) GeocodeCompletionHandler geocodeCompletionHandler;

- (instancetype)initWithPostalCode:(NSString *)postalCode completionHandler:(GeocodeCompletionHandler)geocodeCompletionHandler;

@end

和实现(注意,main 方法是这里唯一有趣的部分......所有其余的都是例行的并发 NSOperation 子类代码;就我个人而言,我移动了所有将并发的 NSOperation 填充到一个基类中,它会清理这个 GeocodeOperation 代码,但我不想进一步混淆它,所以我保持简单) :

//  GeocodeOperation.m

#import "GeocodeOperation.h"
@import CoreLocation;

@interface GeocodeOperation ()

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

@property (nonatomic, copy) NSString *postalCode;

@end

@implementation GeocodeOperation

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

- (CLGeocoder *)sharedGeocoder
{
static CLGeocoder *geocoder = nil;

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
geocoder = [[CLGeocoder alloc]init];
});

return geocoder;
}

- (instancetype)initWithPostalCode:(NSString *)postalCode completionHandler:(GeocodeCompletionHandler)geocodeCompletionHandler
{
self = [super init];
if (self) {
_postalCode = [postalCode copy];
_geocodeCompletionHandler = geocodeCompletionHandler;
}
return self;
}

- (void)main
{
[[self sharedGeocoder] geocodeAddressString:self.postalCode completionHandler:^(NSArray *placemarks, NSError *error) {
if (self.geocodeCompletionHandler) {
self.geocodeCompletionHandler(placemarks, error);
}

[self completeOperation];
}];
}

#pragma mark - NSOperation methods

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

self.executing = YES;

[self main];
}

- (void)completeOperation
{
self.executing = NO;
self.finished = YES;
}

- (BOOL)isConcurrent
{
return YES;
}

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

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

@end

关于ios - 按距离对 UITableView 进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24747834/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com