I'm relatively new to iPhone programming so I apologize if this seems a simple question. I have latitude/location columns in my table (FLOAT type) that I am trying to retrieve from my SQLite database.
I can retrieve my character/text based db columns, but don't know how to retrieve my float values. Should I be formatting the attributes using NSString or something else? I wish to use the float values further downstream with CLLocationDistance.
// the array of locations that we will create
NSMutableArray *locations = [[[NSMutableArray alloc] init] autorelease];
const char *sql = "SELECT locations.name, \
locations.address, \
locations.city, \
locations.state, \
locations.phone, \
locations.zip, \
locations.latitude, \
locations.longitude \
FROM locations \
WHERE category = ?1";
// the sqlite statement object that will hold our result set
sqlite3_stmt *statement;
// prepare the statement to compile the SQL query into byte-code
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
// reset query before execution
sqlite3_reset(statement);
// set bind variable
sqlite3_bind_text(statement, 1, [categoryParameter UTF8String], -1, SQLITE_TRANSIENT);
if ( sqlResult== SQLITE_OK) {
// step through the results - once for each row
while (sqlite3_step(statement) == SQLITE_ROW) {
// allocate a location object to add to the pharmacies array
Location *location = [[Location alloc] init];
// the second parameter is the column index (0 based) in
// the result set
char *name = (char *)sqlite3_column_text(statement, 0);
char *address = (char *)sqlite3_column_text(statement, 1);
char *city = (char *)sqlite3_column_text(statement, 2);
char *state = (char *)sqlite3_column_text(statement, 3);
char *phone = (char *)sqlite3_column_text(statement, 4);
char *zipcode = (char *)sqlite3_column_text(statement, 5);
float latitude = (float) sqlite3_column_double(statement, 6);
float longitude = (float) sqlite3_column_double(statement, 7);
// set all attributes of the location
location.name = (name) ? [NSString stringWithUTF8String:name] : #"";
location.address = (address) ? [NSString stringWithUTF8String:address] : #"";
location.city = (city) ? [NSString stringWithUTF8String:city] : #"";
location.state = (state) ? [NSString stringWithUTF8String:state] : #"";
location.phone = (phone) ? [NSString stringWithUTF8String:phone] : #"";
location.zipcode = (zipcode) ? [NSString stringWithUTF8String:zipcode] : #"";
[locations addObject:location];
[location release];
}
// finalize the statement to release its resources
sqlite3_finalize(statement);
Are the latitude and longitude stored as degrees in the table? Does your Location object have a CLLocationCoordinate2D property called, say, coordinates to put the coordinates in?
If yes, just set the values directly because CLLocationDegrees is actually just a double. For example:
CLLocationCoordinate2D coords;
coords.latitude = sqlite3_column_double(statement, 6);
coords.longitude = sqlite3_column_double(statement, 7);
location.coordinates = coords;
Related
I am trying to get the latitude and longitude of certain regions stored in my database and to store them in an array. I have to store the values as float types. I am getting other values by the following code:
NSString *walkQuery = [[NSString alloc] initWithFormat:#"SELECT Wid,WName,SName,Latitude,Longitude from Walks,SubRegions WHERE Walks.Sid=SubRegions.Sid AND Rid = %d",[regionId integerValue] ];
sqlite3_stmt *walkstatement = nil;
if (sqlite3_prepare_v2(walkNameDB,[walkQuery UTF8String], -1, &walkstatement, nil) == SQLITE_OK)
{
while( sqlite3_step(walkstatement) == SQLITE_ROW )
{
NSNumber *WId;
int temp1 = (int)sqlite3_column_int(walkstatement, 0);
WId = [[NSNumber alloc] initWithInt:temp1];
char *WNameCharacter;
WNameCharacter = (char *) sqlite3_column_text(walkstatement, 1);
NSString *WNameString = [[NSString alloc] initWithUTF8String:WNameCharacter];
char *SNameCharacter;
SNameCharacter = (char *) sqlite3_column_text(walkstatement, 2);
NSString *SNameString = [[NSString alloc] initWithUTF8String:SNameCharacter];
NSMutableDictionary *tempWalk = [[NSMutableDictionary alloc] init];
[tempWalk setObject:WId forKey:#"WalkId"];
[tempWalk setObject:WNameString forKey:#"WalkName"];
[tempWalk setObject:SNameString forKey:#"SubRegionName"];
[regionWalkArray addObject:tempWalk];
Is their any way by which I can get the two float values of latitude and longitude also like I am doing in my code?
Please suggest....
You can use:
float latitude = (float) sqlite3_column_double(walkstatement, 3);
float longitude = (float) sqlite3_column_double(walkstatement, 4);
And can store in dictionary like:
[tempWalk setObject:[NSNumber numberWithFloat:latitude] forKey:#"latitude"];
[tempWalk setObject:[NSNumber numberWithFloat:longitude] forKey:#"longitude"];
You can retrieve it like:
float latitude = [[tempWalk objectForKey:#"latitude"] floatValue];
float longitude = [[tempWalk objectForKey:#"longitude"] floatValue];
Function HEX is one of the core functions in sqlite
I would like to call the function from my objective-c code without actually creating a database in my app .. and so on.
What would be the simplest way to call the function with the least addition of classes?
I found lots of functions written in o-c that HEX a string. However, they are not correct as they produce results different from the HEX function of mysql.
Solution: Converting a string to its Hex value
+(NSString *) stringToHex:(NSString *)str
{
NSString *aResult;
sqlite3 *database;
if(sqlite3_open(":memory:", &database) == SQLITE_OK)
{
NSString *sqlStatement = [NSString stringWithFormat:#"select HEX('%#')",str];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [sqlStatement cStringUsingEncoding:NSUTF8StringEncoding], -1, &compiledStatement, NULL) == SQLITE_OK) {
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
aResult = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return aResult;
}
You can open an in-memory db using sqlite3_open and use that. To do this, open a db with the file name :memory: (w/ the colons).
If you only want the hex function, you can also look into the source code of SQLite. It's plain C and in the public domain.
You can easely retrieve HEX string from a NSDate instance:
NSString *tokenKey = [[[deviceToken description] stringByTrimmingCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#"<>"]]
stringByReplacingOccurrencesOfString:#" " withString:#""];
Sounds like you just want to convert an NSString to hex. You could search on here for a better solution, or here's one I just contrived:
+ (NSString *)stringToHex:(NSString *)string
{
NSUInteger hexLength = ([string length] * 2) + 1;
char *hex = (char *)malloc(sizeof(char) * hexLength);
if (hex == NULL)
return (#"");
const char *cString = [string cStringUsingEncoding:NSASCIIStringEncoding];
for (NSUInteger len = 0, pos = 0; len < [string length]; len++, pos += 2)
snprintf(hex + pos, 3, "%2x", cString[len]);
hex[hexLength] = '\0';
NSString *hexString = [NSString stringWithCString:hex encoding:NSASCIIStringEncoding];
if (hex != NULL)
free(hex);
return (hexString);
}
I was able to get a list of title of the books (tableview) and when i select the book i would like to push to the new view of the details of the books. Do i do it in titleView class 'didSelectRow' or in DetailView class 'viewWillAppear' and if so what exactly do I have to put to get the statement, 3 or contentInfo?
Database Class
(NSArray *) itemsByAuthorID:(NSInteger)authorID {
NSMutableArray *retval = [[NSMutableArray alloc] init];
NSString *query;
code....
query = [NSString stringWithFormat:#"select * from books where books.author_id = '%i'", authorID];
}
code...
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) == SQLITE_OK){
while (sqlite3_step(statement) == SQLITE_ROW) {
int itemID = sqlite3_column_int(statement, 0);
int authorID = sqlite3_column_int(statement, 1);
char *nameChars = (char *) sqlite3_column_text(statement, 2);
char *itemContent = (char *) sqlite3_column_text(statement, 3);
NSString *contentTitle = [[NSString alloc] initWithUTF8String:nameChars];
NSString *contentInfo = [[NSString alloc] initWithUTF8String:itemContent];
Item *info = [[Item alloc] initWithItemID:itemID authorID:authorID contentTitle:(NSString *)contentTitle contentInfo:contentInfo];
[retval addObject:info];
}
sqlite3_finalize(statement);
}
return retval;
You can create a private class for Book and retrive data from database for all books in array of Book.
Then after when didSelectRow is called only pass object of Book as parameter and show details in Detail view.
]i have this graph that shows the last 7 records from my sqlite database, it works.
but i will like to know the absolute last 7 days.
this is my codes
if ([appDelegate.drinksOnDayArray count] >=7)
{
drunked = 7;
}
else {
drunked = [appDelegate.drinksOnDayArray count];
}
if (drunked !=0)
{
if (drunked<7) {
for (int i=drunked; i<7; i++) {
//DayOfDrinks *drinksOnDay = [appDelegate.drinksOnDayArray objectAtIndex:i-1];
NSString * dayString= [NSString stringWithFormat:#"Nil"];//[NSDate stringForDisplayFromDateForChart:drinksOnDay.dateConsumed];
[dayArray addObject:dayString];//X label for graph the day of drink.
}
}
for(int i=drunked; i>0; i--)
{
DayOfDrinks *drinksOnDay = [appDelegate.drinksOnDayArray objectAtIndex:i-1];
NSString * dayString= [NSDate stringForDisplayFromDateForChart:drinksOnDay.dateConsumed];
[dayArray addObject:dayString];//X label for graph the day of drink.
drinksOnDay.isDetailViewHydrated = NO;
[drinksOnDay hydrateDetailViewData];
NSNumber *sdNumber = drinksOnDay.standardDrinks; // pass value over to Standard Drink Numbers
//[sdArray addObject: sdNumber];
float floatNum = [sdNumber floatValue]; // convert sdNumber to foat
[sdArray addObject:[NSNumber numberWithFloat:floatNum]];//add float Value to sdArray
}
//Get max value using KVC
fMax = [[sdArray valueForKeyPath:#"#max.floatValue"] floatValue];
//Ceiling the max value
imax = (int)ceilf(fMax);
//Odd check to make even by checking right most bit
imax = (imax & 0x1) ? imax + 1 : imax;
NSMutableArray *array = [NSMutableArray arrayWithCapacity:(imax / 2) + 1];
//Assuming all numbers are positive
for(int i = 0; i <= imax; i +=2)
{
[array addObject:[NSString stringWithFormat:#"%d", i]];
}
NSLog(#"Array Value %#", array);
NSLog(#"Day Array%#", dayArray);
NSString *sData[drunked];// = malloc(7 * sizeof(NSString *));
for (int i=0; i<drunked; i++)
{
DayOfDrinks *drinksOnDay = [appDelegate.drinksOnDayArray objectAtIndex:i];
sData[i] = [NSString stringWithFormat:#"%#",drinksOnDay.standardDrinks];
}
NSLog(#"sdArray %#",sdArray);
if (drunked<7) {
for (int i=drunked; i<7; i++) {
sData[i]=[NSString stringWithFormat:#"0"];
}
}
my sqlite statement
- (void) hydrateDetailViewData {
//If the detail view is hydrated then do not get it from the database.
if(isDetailViewHydrated) return;
self.standardDrinks = [NSDecimalNumber zero];
NSDecimalNumber *decimal = [NSDecimalNumber zero];
if(detailStmt == nil) {
const char *sql = "SELECT volume, percentage FROM consumed WHERE DATE(datetime) = ?";
if(sqlite3_prepare_v2(database, sql, -1, &detailStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating detail view statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_bind_text(detailStmt, 1, [[NSDate stringFromDate:self.dateConsumed withFormat:#"yyyy-MM-dd"] UTF8String], -1, SQLITE_TRANSIENT);
static NSDecimalNumberHandler* roundingBehavior = nil;
if (roundingBehavior == nil) {
roundingBehavior =
[[NSDecimalNumberHandler alloc] initWithRoundingMode:NSRoundPlain scale:1 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
}
while(sqlite3_step(detailStmt) == SQLITE_ROW) {
double volumeDN = sqlite3_column_double(detailStmt, 0);
double percentageDN = sqlite3_column_double(detailStmt, 1);
double drinks = ((volumeDN/1000) * percentageDN);
NSDecimalNumber *drinksDec = [[NSDecimalNumber alloc] initWithDouble:drinks];
NSDecimalNumber *countryRate = [[NSDecimalNumber alloc] initWithDouble:0.789];
decimal = [decimal decimalNumberByAdding:[drinksDec decimalNumberByMultiplyingBy:countryRate]];
//NSLog([NSString stringWithFormat:#"Standard Drinks - %#", self.standardDrinks]);
}
self.standardDrinks = [decimal decimalNumberByRoundingAccordingToBehavior:roundingBehavior];
//Reset the detail statement so it can be used again without preparing the statement again.
sqlite3_reset(detailStmt);
//Set isDetailViewHydrated as YES, so we do not get it again from the database.
isDetailViewHydrated = YES;
}
+ (void) getInitialDataToDisplay:(NSString *)dbPath {
DrinkTabsAndNavAppDelegate *appDelegate = (DrinkTabsAndNavAppDelegate *)[[UIApplication sharedApplication] delegate];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
const char *sql = "SELECT DATE(datetime) FROM consumed GROUP BY DATE(datetime) ORDER BY datetime DESC";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSString *dateDrunk = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 0)];
NSDate *theDate = [NSDate dateFromString:dateDrunk withFormat:#"yyyy-MM-dd"];
DayOfDrinks *drinkDayObj = [[DayOfDrinks alloc] initWithDateConsumed:theDate];
[drinkDayObj hydrateDetailViewData];
//NSLog([NSDate stringFromDate:drinkDayObj.dateConsumed withFormat:#"yyyy-MM-dd"]);
[appDelegate.drinksOnDayArray addObject:drinkDayObj];
[drinkDayObj release];
}
}
}
else
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
Without going through those blocks of code, I'll hazard a guess here:
SELECT * FROM CONSUMED WHERE DATE BETWEEN ? AND ?
Set up a date 7 days ago (7*24*60*60*1000 milliseconds ago), as well as now, and bind those to the question marks.
Hi after several hours searching i have found the function which gives me memory leaks. The leaks i get are:
Leaked Object#AddressSize Responsible Library Responsible Frame
NSCFString 2 < multiple > 32 Foundation
-[NSPlaceholderString initWithBytes:length:encoding:]
i cant see anything wrong with this code. any help would be gratefully received Dan
-(void)readItems {
if (!database) return; // earlier problems
// build select statement
if (!selStmt)
{
const char *sql = "SELECT * FROM Demotivate order by name asc;";
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
{
selStmt = nil;
}
}
if (!selStmt)
{
NSAssert1(0, #"Can't build SQL to read items [%s]", sqlite3_errmsg(database));
}
// loop reading items from list
[items removeAllObjects]; // clear list for rebuild
int ret;
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{ // get the fields from the record set and assign to item
// primary key
NSInteger n = sqlite3_column_int(selStmt, 0);
Item *item = [[Item alloc] initWithPrimaryKey:n]; // create item
// item name
char *s = (char *)sqlite3_column_text(selStmt, 1);
if (s==NULL) s = "";
item.name = [NSString stringWithUTF8String:(char *)s];
// quantity needed
item.howOften = sqlite3_column_int(selStmt, 3);
// noted
s = (char *)sqlite3_column_text(selStmt, 2);
if (s==NULL) s = "";
item.Cost = [NSString stringWithUTF8String:(char *)s];
s = (char *)sqlite3_column_text(selStmt, 4);
if (s==NULL) s = "";
item.income = [NSString stringWithUTF8String:(char *)s];
s = (char *)sqlite3_column_text(selStmt, 5);
if (s==NULL) s = "";
item.wage = [NSString stringWithUTF8String:(char *)s];
[items addObject:item]; // add to list
[item release];
// free item
}
sqlite3_reset(selStmt); // reset (unbind) statement
}
Probably you forgot to release item.name in Item's dealloc.