1

I have an SQL DB that contains Lat and Long info. I have found my current location and been able to get the distance of each location from my current location. I can get my tableview to show this distance, but know I want to sort that tableview so the closest are listed first.

My thought is I will need to add the distance to my SQL DB data, sort that some how and then display that info back to the tableview.

My thought is I would do all of this within my TableView. Looking for guidance on how to do this and if I should be doing it in the 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]];
}

For reference the rest of my code

Bars.h

#import <Foundation/Foundation.h>

@interface Bars : NSObject {
    NSString *barName;
    NSString *barAddress;
    NSString *Lat;
    NSString *Long;
    NSString *cachedDist;
}

@property (nonatomic, copy) NSString *barName;
@property (nonatomic, copy) NSString *barAddress;
@property (nonatomic, copy) NSString *Lat;
@property (nonatomic, copy) NSString *Long;
@property (nonatomic, copy) NSString *cachedDist;

- (id)initWithName:(NSString *)name address:(NSString *)address latitude:(NSString *)latitude longitude:(NSString *)longitude distance:(NSString *)distance;

@end

Bars.m

#import "Bars.h"

@implementation Bars

@synthesize barName = _barName;
@synthesize barAddress = _barAddress;
@synthesize Lat = _Lat;
@synthesize Long = _Long;
@synthesize cachedDist = _cachedDist;

- (id)initWithName:(NSString *)name address:(NSString *)address latitude:(NSString *)latitude longitude:(NSString *)longitude distance:(NSString *)distance;
{
if ((self = [super init])) {
    self.barName = name;
    self.barAddress = address;
    self.Lat = latitude;
    self.Long = longitude;
    self.cachedDist = distance;
}
return self;
}

@end

BarDatabase.h

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

@interface BarDatabase : NSObject
{
    sqlite3 *_database;
}

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

@end

BarDatabase.m

#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
4

1 に答える 1

0

うーん。cellForRowAtIndexPath 内でソートが行われてはなりません。ゲームでは遅すぎます。各セルが 1 つのバーで、バーを距離で並べ替える必要がある場合は、self.barInfo の遅延ゲッターで並べ替えを行うことをお勧めします (それがバーのリストである場合)。

モデルがどのように見えるかはわかりませんが、各棒オブジェクトに基準点からの距離のプロパティがある場合、並べ替えはそこにあるものと似ています。

この並べ替えは、最初のセルがロードされたとき (「遅延」部分) にのみ発生し、キャッシュされます。したがって、 cellForRowAtIndexPath: は、正しい順序であると信頼して、indexPath の行にあるモデル オブジェクトを要求するだけです。

あなたがこの用語にどの程度精通しているかはわかりませんので、お気軽に明確な質問をしてください。回答を繰り返します.

より多くのコードを共有した後に編集: @property を cachedDistance のようなものと呼ばれるバーに追加し、画面に表示されるたびに (viewWillAppear)、バーを反復処理してキャッシュされた距離を設定する必要があると思います (cellForRow にあるものと同様のコードを使用) ...)。次に、self.barArray: のゲッターを実装します。-(NSArray *)barArrayこれは基本的に、キャッシュされた距離プロパティの名前をキーとして、sortDescriptor を使用して並べ替えられた barArray を返します。これにより、cellForRow... コードが大幅に簡素化されます。

その後、ロジックを拡張して、位置の更新を取得したときに距離を再計算できます。これは、以前の距離から特定の距離である場合にのみ可能です。

于 2012-06-21T02:38:17.553 に答える