Ios 按距离当前位置的距离对TableView排序

Ios 按距离当前位置的距离对TableView排序,ios,xcode,sqlite,Ios,Xcode,Sqlite,我有一个包含Lat和Long信息的sqldb。我已经找到了我的当前位置,并且能够得到每个位置到我当前位置的距离。我可以让我的tableview显示这个距离,但我知道我想对该tableview进行排序,以便首先列出最近的tableview 我的想法是,我需要将距离添加到SQL DB数据中,对其进行排序,然后将该信息显示回tableview #import "TulsaMasterViewController.h" #import "TulsaDetailViewController.h" #imp

我有一个包含Lat和Long信息的sqldb。我已经找到了我的当前位置,并且能够得到每个位置到我当前位置的距离。我可以让我的tableview显示这个距离,但我知道我想对该tableview进行排序,以便首先列出最近的tableview

我的想法是,我需要将距离添加到SQL DB数据中,对其进行排序,然后将该信息显示回tableview

#import "TulsaMasterViewController.h"
#import "TulsaDetailViewController.h"
#import "Bars.h"
#import "BarDatabase.h"

@implementation TulsaMasterViewController

@synthesize barArray = _barArray;
@synthesize currentLat = _currentLat;


- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
currentLat = newLocation;

if (newLocation.horizontalAccuracy <= 100.0f) {
    [lm stopUpdatingLocation];
}

[self.tableView reloadData];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSString *msg = [[NSString alloc]initWithString:@"Error obtaining location"];
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Error" message:msg delegate:nil cancelButtonTitle:@"Done" otherButtonTitles:nil];
[alert show];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.barArray count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}

//Get the object from the array.
Bars *barObj = [self.barInfo objectAtIndex:indexPath.row];

//Set the name.
cell.textLabel.text = barObj.barName;

if (currentLat == nil) {
    cell.detailTextLabel.text = [NSString stringWithFormat:@"?"];
}else
{
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%.02f", cachedDist];
}

// Set up the cell
return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"ShowDetails"]) {
    TulsaDetailViewController *detailViewController = [segue destinationViewController];

    detailViewController.detailItem = [self.barArray objectAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}

- (void)viewDidLoad
{
[super viewDidLoad];

self.barArray = [BarDatabase database].barInfo;

lm = [[CLLocationManager alloc] init];
lm.delegate = self;
[lm startUpdatingLocation];
}

- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];

for (Bars *barObj in barArray) {
    NSString *strLat = barObj.Lat;
    NSString *strLong = barObj.Long;
    CLLocation *barLocation = [[CLLocation alloc] initWithLatitude:[strLat doubleValue] longitude:[strLong doubleValue]];
    CLLocationDistance distance = [currentLat distanceFromLocation:barLocation]/1000;

    [barArray addObject:[NSNumber numberWithDouble:distance]];
    NSSortDescriptor *sort=[NSSortDescriptor sortDescriptorWithKey:@"cachedDist" ascending:YES];
    [barArray sortUsingDescriptors:[NSArray arrayWithObject:sort]];
}
我的想法是,我会在我的TableView中完成所有这些。正在寻找有关如何执行此操作以及是否应该在tableview中执行此操作的指导

#import "TulsaMasterViewController.h"
#import "TulsaDetailViewController.h"
#import "Bars.h"
#import "BarDatabase.h"

@implementation TulsaMasterViewController

@synthesize barArray = _barArray;
@synthesize currentLat = _currentLat;


- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
currentLat = newLocation;

if (newLocation.horizontalAccuracy <= 100.0f) {
    [lm stopUpdatingLocation];
}

[self.tableView reloadData];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSString *msg = [[NSString alloc]initWithString:@"Error obtaining location"];
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Error" message:msg delegate:nil cancelButtonTitle:@"Done" otherButtonTitles:nil];
[alert show];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.barArray count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}

//Get the object from the array.
Bars *barObj = [self.barInfo objectAtIndex:indexPath.row];

//Set the name.
cell.textLabel.text = barObj.barName;

if (currentLat == nil) {
    cell.detailTextLabel.text = [NSString stringWithFormat:@"?"];
}else
{
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%.02f", cachedDist];
}

// Set up the cell
return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"ShowDetails"]) {
    TulsaDetailViewController *detailViewController = [segue destinationViewController];

    detailViewController.detailItem = [self.barArray objectAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}

- (void)viewDidLoad
{
[super viewDidLoad];

self.barArray = [BarDatabase database].barInfo;

lm = [[CLLocationManager alloc] init];
lm.delegate = self;
[lm startUpdatingLocation];
}

- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];

for (Bars *barObj in barArray) {
    NSString *strLat = barObj.Lat;
    NSString *strLong = barObj.Long;
    CLLocation *barLocation = [[CLLocation alloc] initWithLatitude:[strLat doubleValue] longitude:[strLong doubleValue]];
    CLLocationDistance distance = [currentLat distanceFromLocation:barLocation]/1000;

    [barArray addObject:[NSNumber numberWithDouble:distance]];
    NSSortDescriptor *sort=[NSSortDescriptor sortDescriptorWithKey:@"cachedDist" ascending:YES];
    [barArray sortUsingDescriptors:[NSArray arrayWithObject:sort]];
}
BarDatabase.h

#import <Foundation/Foundation.h>
#import <sqlite3.h>

@interface BarDatabase : NSObject
{
    sqlite3 *_database;
}

+ (BarDatabase *)database;
- (NSMutableArray *)barInfo;

@end

人力资源管理。cellForRowAtIndexPath内部不应发生排序。比赛已经太晚了。如果每个单元格为1条,并且这些条应按距离排序,我建议您在lazy getter for your.barInfo(如果这是条列表)中实现排序

我不确定你的模型是什么样子的,但如果每个条对象都有一个属性,表示与参考点之间的距离,那么你的排序将与你的排序相似

只有在加载第一个单元格(即“惰性”部分)然后缓存时,才会发生这种排序。因此,您的cellForRowAtIndexPath:只需在其indexPath行中请求模型对象,并相信其顺序正确

我不确定您对这些术语熟悉多少,所以请随意提出澄清问题,我将重复回答

共享更多代码后编辑: 我认为您应该向条中添加一个名为cachedDistance的@property,每当您出现在屏幕上时(ViewWillDisplay),就在条上迭代并设置它们的缓存距离(使用与cellForRow中类似的代码…)。然后为self.barArray实现一个getter:
-(NSArray*)barArray
,该getter本质上返回使用sortDescriptor排序的barArray,其中缓存的距离属性的名称作为其键。这将简化你的手机。。。代码很多


然后,当您获得位置更新时,您可以扩展逻辑以重新计算距离,可能只有在距离上一个位置有一定距离时。

属性(非原子,复制)NSString*barName;属性(非原子,复制)NSString*barAddress;属性(非原子,副本)NSString*Lat;属性(非原子,复制)NSString*Long;最初,我的数据库中没有实际的距离字段。在cellForRowAtIndexPath下,我计算出每行加载时的距离。我认为,为了保持与正确行相关的距离,我需要将距离添加到数组中,并在cellForRowAtIndexPath下进行排序。Setup bar.h/m Define Fields BarDatabase.h/m Pull数据位置在MasterViewController中可以发送u代码您可以用它编辑您的初始帖子,这将允许格式化,其他人会注意到:-)我想我理解。我已经更新了上面的代码,开始执行上面所说的操作,但是我遇到了ViewWillDisplay下的第一个问题。它不喜欢XPath。我倾向于同意,但我不确定如何拉动每一行来计算距离。如果我误解了你,请告诉我。你视图中的逻辑需要更新,它不能与cellForRow中的逻辑相同。在你的条上应该有一个迭代,设置每个条的缓存距离。仔细考虑一下这个过程。在ViewWillDisplay中,您只需“设置”数组,其中包括加载条,然后迭代每个条(而不是尝试使用索引路径加载条)并计算/设置距离。然后对数组进行排序并将其存储在cellForRow中供以后使用。。。
#import <Foundation/Foundation.h>
#import <sqlite3.h>

@interface BarDatabase : NSObject
{
    sqlite3 *_database;
}

+ (BarDatabase *)database;
- (NSMutableArray *)barInfo;

@end
#import "BarDatabase.h"
#import "Bars.h"

@implementation BarDatabase

static BarDatabase *_database;

+ (BarDatabase *)database {
if (_database == nil) {
    _database = [[BarDatabase alloc] init];
}
return _database;
}

- (id)init {
if ((self = [super init])) {
    NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:@"TulsaBars" 
                                                         ofType:@"sqlite"];

    if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) {
        NSLog(@"Failed to open database!");
    }
}
return self;
}

- (void)dealloc {
sqlite3_close(_database);
}

- (NSMutableArray *)barInfo {

NSMutableArray *retval = [[NSMutableArray alloc] init];
NSString *query = @"SELECT * FROM TulsaBars";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) 
    == SQLITE_OK) {
    while (sqlite3_step(statement) == SQLITE_ROW) {
        char *nameChars = (char *) sqlite3_column_text(statement, 1);
        char *addressChars = (char *) sqlite3_column_text(statement, 2);
        char *latChars = (char *) sqlite3_column_text(statement, 8);
        char *longChars = (char *) sqlite3_column_text(statement, 9);
        NSString *name = [[NSString alloc] initWithUTF8String:nameChars];
        NSString *address = [[NSString alloc] initWithUTF8String:addressChars];
        NSString *latitude = [[NSString alloc] initWithUTF8String:latChars];
        NSString *longitude = [[NSString alloc] initWithUTF8String:longChars];

        Bars *info = [[Bars alloc]
                      initWithName:name address:address latitude:latitude longitude:longitude];                        
        [retval addObject:info];
    }
    sqlite3_finalize(statement);
}
return retval;

}
@end