SQLITE3 inserting a null value - ios4

sqlite3_bind_int(statement, 1, nil);
How can I add a null in my above statement , as I am making this field auto increment.
Here's my code :
if (sqlite3_open([[self dataFilePath] UTF8String], &database)!= SQLITE_OK)
{
sqlite3_close(database);
NSAssert(0, #"Failed to open database");
}
NSLog(#"json count ========== %i",[jsonArray count]);
for (int i =0 ; i < [jsonArray count]; i++)
// while (i < [jsonArray count])
{
dictionary = [jsonArray objectAtIndex:i];
char *errorMsg;
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(database, [insertQuery UTF8String], -1, &statement, nil) == SQLITE_OK)
{
// NSLog(#"%#",[dictionary valueForKey:#"text"]);
sqlite3_bind_null(statement, 1);
sqlite3_bind_text(statement, 2, [[dictionary valueForKey:#"date"] UTF8String], -1, NULL);
// NSLog(#"date %#",[dictionary valueForKey:#"date"]);
sqlite3_bind_text(statement, 3, [[dictionary valueForKey:#"text"] UTF8String], -1, NULL);
// NSLog(#"text %#",[dictionary valueForKey:#"text"]);
}
if (sqlite3_step(statement) != SQLITE_DONE)
{
NSAssert1(0, #"Error updating table: %s", errorMsg);
sqlite3_finalize(statement);
}
sqlite3_close(database);
}
To select :
sqlite3 *database;
if (sqlite3_open([[self dataFilePath] UTF8String], &database)
!= SQLITE_OK) { sqlite3_close(database);
NSAssert(0, #"Failed to open database");
}
NSString *query = [self selectQueryInDB];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [query UTF8String],
-1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW)
{
int row = sqlite3_column_int(statement, 0);
if (row == indexPathRow+1)
{
char *field1 = (char *)sqlite3_column_text(statement, 1);
char *field2 = (char *)sqlite3_column_text(statement, 2);
NSString *f1 = [[NSString alloc] initWithUTF8String:field1];
NSString *f2 = [[NSString alloc] initWithUTF8String:field2];
NSString *fullData = [NSString stringWithFormat:#"%# %#",f1,f2];
NSLog(#"%#",fullData);
}
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
I am getting SIGABRT in NSString *f1 as *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSPlaceholderString initWithUTF8String:]: NULL cString'
Please tell me what i am doing wrong.

sqlite3_bind_int(statement, 1, nil) will bind 0 to the first bind point, not NULL. 0 and NULL are not the same things in SQL.
I think you're looking for sqlite3_bind_null. It binds NULL to a bind point, as in:
sqlite3_bind_null(statement, 1);
There's no parameter here for NULL; it's in the name of the function.
Also, unbound parameters default to NULL. So unless you're using sqlite3_reset, you shouldn't need to use this at all.
(Since we're on the topic of bindings and resets, I should mention sqlite3_clear_bindings, which binds all parameters to NULL.)
Problem 2
You updated this to mention a SIGABRT in the NSString *f1 line.
There's two problems with your code that I see:
sqlite3_column_text is 0 based; the first column is 0, not 1. (Yes, columns are 0 based. Even though bindings are 1-based.)
char *field1 = (char *)sqlite3_column_text(statement, 1);
should be:
char *field1 = (char *)sqlite3_column_text(statement, 0);
sqlite3_column_text can return NULL if NULL is in the data, but initWithUTF8String: does not accept NULL as a value.
I suggest doing this:
NSString *f1 = field1 ? [[NSString alloc] initWithUTF8String:field1] : nil;
Using this, you'll end up with a nil NSString if you had a NULL column in the data. You can make decisions on this, and it's easy to do f1 ?: #"" when you really need a string.
Another approach is to change the query:
SELECT Field FROM Table;
To:
SELECT COALESCE(Field,'') FROM Table;
You'll no longer be able to tell if Field was originally NULL, but maybe you don't care.

Related

For Loop from Core Data

I have a question, I have 2 arrays (date and descriere), one is keeping a date which I select from a datePicker the other one is an array with strings, Both arrays are fetched from CoreData.
-(void)generateLocalNotification {
CoreDataStack *coreDataStack = [CoreDataStack defaultStack];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"AddEntrySettings"];
fetchRequest.resultType = NSDictionaryResultType;
NSArray *result = [coreDataStack.managedObjectContext executeFetchRequest:fetchRequest error:nil];
NSMutableArray *date = [result valueForKey:#"date"];
NSMutableArray *descriere = [result valueForKey:#"descriere"];`
if (date != nil) {
for (NSString *stringDate in date) {
NSDateFormatter *format = [[NSDateFormatter alloc]init];
[format setDateFormat:#"MM/dd/yyyy h:mm a"];
[format setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
self.date = [format dateFromString:stringDate];
NSLog(#"LOG:%#",date);
localNotification.fireDate = [self.date dateByAddingTimeInterval:0];
localNotification.timeZone = [NSTimeZone timeZoneWithName:#"GMT"];
for (int i = 0; i < descriere.count; i++) {
localNotification.alertBody = descriere[i];
}
localNotification.applicationIconBadgeNumber = 1;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.userInfo = #{#"id" : #42};
UIApplication *app = [UIApplication sharedApplication];
[app scheduleLocalNotification:localNotification];
}
}
}
When I try to fireDate everything is working fine, every time when a date from array is matching with local time I receive a notification till I try to add alertBody, when I make a for loop for alertBody every time is showing just last entry from my NSArray. In CoreData the both entries I adding in the same time. Where is my mistake? How can I make every time to receive a notification with alertBody that matching with date that I insert in CoreData?
The problem is that this for loop:
for (int i = 0; i < descriere.count; i++) {
localNotification.alertBody = descriere[i];
}
will, for every stringDate, iterate to the last item in your descriere array. What you want is to find the index of stringDate in date, and then find the string at the same index in descriere.
But there is an easier way. Don't unpack result into two separate arrays, just access the different values from within the for loop:
if (result != nil) {
for (NSDictionary *dict in result) {
NSString *stringDate = [dict objectForKey:#"date"];
// if necessary, test whether stringDate is nil here
NSDateFormatter *format = [[NSDateFormatter alloc]init];
[format setDateFormat:#"MM/dd/yyyy h:mm a"];
[format setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
self.date = [format dateFromString:stringDate];
NSLog(#"LOG:%#",date);
localNotification.fireDate = [self.date dateByAddingTimeInterval:0];
localNotification.timeZone = [NSTimeZone timeZoneWithName:#"GMT"];
localNotification.alertBody = [dict objectForKey:#"descriere"];
localNotification.applicationIconBadgeNumber = 1;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.userInfo = #{#"id" : #42};
UIApplication *app = [UIApplication sharedApplication];
[app scheduleLocalNotification:localNotification];
}
}

Changes to Core Data are not saved when use deletedObjects:entity.attributeName

I am trying to delete the value of some Attributes in two linked Entities. Here is the code I am using:
+ (MeetPhoto *)deletePhotoForSelectedMeet:(MarksFromMeets *)specificMeet
inManagedObjectContext:(NSManagedObjectContext *)context;
{
MeetPhoto *results = nil;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"MarksFromMeets"];
request.predicate = [NSPredicate predicateWithFormat:#"uniqueResultID = %#", specificMeet.uniqueResultID];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"uniqueResultID" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSError *error = nil;
NSArray *matches = [context executeFetchRequest:request error:&error];
if (!matches || [matches count] > 1) {
NSLog(#"There has been an error in matches in %#: \n%#.\n matches count = %lu",
NSStringFromClass([self class]),
NSStringFromSelector(_cmd),
(unsigned long)[matches count]);
} else if ([matches count] == 0){
NSLog(#"There were no matches in %#: \n%#.\n matches count = %lu",
NSStringFromClass([self class]),
NSStringFromSelector(_cmd),
(unsigned long)[matches count]);
} else {
if (debug == 1) NSLog(#"In %# and matches = %lu",NSStringFromClass([self class]),(unsigned long)[matches count]);
for (MarksFromMeets* meetEntity in matches) {
if (debug == 1) NSLog(#" MarksFromMeet = %# \n thumbnail = %# \n photo = %#",meetEntity.meetName,meetEntity.photoThumbNail,meetEntity.whichPhoto.photo);
[context deleteObject:meetEntity.photoThumbNail];
[context deleteObject:meetEntity.whichPhoto.photo];
NSError *mySavingError = nil;
[meetEntity.managedObjectContext save:&mySavingError];
if (mySavingError) NSLog(#"In %# and mySavingError is %#",NSStringFromClass([self class]), mySavingError);
}
}
return results;
}
Where whichPhoto is the title of the link between the two Core Data Entities.
Here is NSLog Statement:
2014-08-13 14:40:45.334 ITrackXC[12054:60b] thisMeetsPhoto should equal nil and equals (null)
2014-08-13 14:41:37.095 ITrackXC[12054:60b] In MeetPhotoViewController and executing imagePickerController:didFinishPickingImage:editingInfo:
2014-08-13 14:41:37.583 ITrackXC[12054:60b] In MeetPhoto and matches = 1
2014-08-13 14:41:37.589 ITrackXC[12054:60b] whichMeetPhotographed = <MarksFromMeets: 0x1700c5be0> (entity: MarksFromMeets; id: 0xd000000000300004 <x-coredata://ED56838C-9F27-451D-97CA-01AF0FC38830/MarksFromMeets/p12> ; data: {
athleteGrade = "12th Grade";
event = "5000 Meters";
eventPR = 1;
eventSB = 1;
markInEvent = "19:03";
meetDate = "2013-11-02 07:00:00 +0000";
meetID = 78103;
meetName = "OSAA 3A/2A/1A State Championships";
photoThumbNail = "<UIImage: 0x170281b80>";
placeInEvent = 2;
raceSorter = 5000;
seasonName = 2013;
sortMark = 1143;
standardOrMetric = nil;
uniqueResultID = 10032696;
whichPhoto = "0x178236d80 <x-coredata:///MeetPhoto/t9C5E481D-5911-47C9-AA8B-6015AAD1C23C2>";
whoRan = "0xd000000000080000 <x-coredata://ED56838C-9F27-451D-97CA-01AF0FC38830/AthleteInfo/p2>";
})
photo = <UIImage: 0x17009b440>
thumbnail = <UIImage: 0x170281b80>
2014-08-13 14:41:37.599 ITrackXC[12054:60b] NSManagedObjects did change.
2014-08-13 14:41:39.444 ITrackXC[12054:60b] NSManagedContext did save.
I do not get any errors. However when I look at the TableView where the data is displayed, the photos are still part of the record.
I can get rid of the thumbnail and associated photo by setting them to "nil". Is there any problem with this approach?
Setting attribute values to nil is how you're supposed to do this, so no, there's no problem with it. The deleteObject: method is only for when you want to delete a managed object. Using it in other cases might not crash, but it also won't have the effect you're aiming for.
In the case of the photo, you might need to delete an object, but it's hard to tell from your code. You seem to want to get rid of meetEntity.whichPhoto.photo. I don't know what whichPhoto is; if it's a managed object, you might want to call deleteObject on myEntity.whichPhoto to get rid of it. If nobody else is using it, that is.

Selecting TableView cell returns incorrect object

I followed a tutorial I found online to create a tableview with sections and an index from an array of custom objects. This code works with the exception that when I select a row in the table I the index path for that section and not for the entire array. I can see why it doesn't work but I can't figure out how to address the fix, this is my cell for tableview code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"NameCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
int displayOrder = [defaults integerForKey:#"displayOrder"];
int sortOrder = [defaults integerForKey:#"sortOrder"];
NSString *alphabet = [listIndex objectAtIndex:[indexPath section]];
NSPredicate *sectionPredicate = [[NSPredicate alloc] init];
if (sortOrder == 1) {
//NSLog(#"fName is predicate at cell level");
sectionPredicate = [NSPredicate predicateWithFormat:#"fName beginswith[c] %#", alphabet];
} else {
//NSLog(#"lName is predicate at cell level");
sectionPredicate = [NSPredicate predicateWithFormat:#"lName beginswith[c] %#", alphabet];
}
NSArray *sectionContacts = [filteredList filteredArrayUsingPredicate:sectionPredicate];
if (isSearching) {
current = [filteredList objectAtIndex:indexPath.row];
} else{
current = [sectionContacts objectAtIndex:indexPath.row];
}
if (displayOrder == 1) {
NSString *fullName = [NSString stringWithFormat:#"%# %#",[current valueForKey:#"fName"],[current valueForKey:#"lName"]];
[cell.textLabel setText:fullName];
//NSLog(#"FirstNameFirst");
} else {
NSString *fullName = [NSString stringWithFormat:#"%# %#",[current valueForKey:#"lName"],[current valueForKey:#"fName"]];
[cell.textLabel setText:fullName];
//NSLog(#"LastNameFirst");
}
[cell.detailTextLabel setText:[current valueForKey:#"extension"]];
return cell; }
THen I call the segue with this code.
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"showContact"]) {
DetailViewController *dvc = [segue destinationViewController];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
NSDictionary *c = [filteredList objectAtIndex:path.row];
[dvc setCurrentContact:c];
[searchBar resignFirstResponder];
} }
The problem is that the objectAtIndex:path.row returns the index for that section but it isn't modified for the entire array, so if a name in the "B" section that is at index 4 of that section is tapped it returns the object at index 4 of the primary array. I have been scratching my head to figure out how to get the index for the full array and not for the one that is only local to that section.
I'll buy you a 6 pack of your favorite beverage if you can help!
Thanks!
You do it the same way that they do it in the first function, so change your prepareForSegue to this:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showContact"]) {
DetailViewController *dvc = [segue destinationViewController];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
NSDictionary *c;
NSString *alphabet = [listIndex objectAtIndex:[path section]];
NSPredicate *sectionPredicate = [[NSPredicate alloc] init];
if (sortOrder == 1) {
sectionPredicate = [NSPredicate predicateWithFormat:#"fName beginswith[c] %#", alphabet];
} else {
sectionPredicate = [NSPredicate predicateWithFormat:#"lName beginswith[c] %#", alphabet];
}
NSArray *sectionContacts = [filteredList filteredArrayUsingPredicate:sectionPredicate];
if (isSearching) {
c = [filteredList objectAtIndex:path.row];
} else{
c = [sectionContacts objectAtIndex:path.row];
}
[dvc setCurrentContact:c];
[searchBar resignFirstResponder];
}
}
Note that it would probably be best to pull the common code out and make a separate function instead of using it twice like this.

NSMutableArray removeAllObjects issue

I am trying to remove all the objects from the NSMutableArray and I am reloading the UITableView. But it produces SIGABRT in cellForRowAtIndexPath. The code is given below.
if ([nsMutableArray count] != 0) {
[nsMutableArray removeAllObjects];
[tableView reloadData];
}
It shows SIGABRT in
if (cell == nil) {
cell = (UICustomCell *)[nsMutableArray objectAtIndex:indexPath.row];
}
Help me to come out of this problem.
change this
to
if ([NSMutableArrayObject count] != 0) {
[NSMutableArrayObject removeAllObjects];
[tableView reloadData];
}
if (cell == nil) {
cell = (UICustomCell *)[NSMutableArrayObject objectAtIndex:indexPath.row];
}
You are calling instance methods (count, removeAllObjects, reloadData, objectAtIndex:) on classes (NSMutableArray, UITableView) instead of object instances.

GKLeaderboard posting problems

I am not sure if sandbox is taking too long to update or if my code is funky.
I am simply grabbing the local players last entered score and adding another score to it and trying to post the result.
Here is my code:
- (void) reportScore: (int64_t) score forCategory: (NSString*) category
{
GKScore *scoreReporter = [[[GKScore alloc]initWithCategory:category] autorelease];
scoreReporter.value = score;
[scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
if (error != nil)
{
// handle the reporting error
NSLog(#"Error reporting score");
}
}];
}
-(void)postScore:(int64_t)score forCategory:(NSString *)category {
GKLeaderboard *query = [[GKLeaderboard alloc]init];
query.category = category;
if (query != nil)
{
[query loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil){
// Handle the error.
NSLog(#"Error loading scores");
}
if (scores != nil){
// Process the score.
int64_t newScore = query.localPlayerScore.value + score;
[self reportScore:newScore forCategory:category];
}
}];
}
[query release];
}
Thanks for any help.
EDIT: Sandbox leaderboard has the first score, but will not update the subsequent scores.
Having the same issue at my end. It will provide the score correctly for the first time in a session. After that, it keep sending back the same score even if we update the score in that session.
You need to check property of GKleaderBoard class.For Your Info. see below code.
GKLeaderboardViewController *leaderController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != NULL)
{
leaderController.category = self.currentLeaderBoard;
leaderController.timeScope = GKLeaderboardTimeScopeWeek;
leaderController.leaderboardDelegate = self;
[self presentModalViewController: leaderController animated: YES];
}
AND
you can also check apple docs for both GKLeaderBoard and GKAchievementViewController class below.
for GKLeaderBoard
http://developer.apple.com/library/ios/#documentation/GameKit/Reference/GKLeaderboard_Ref/Reference/Reference.html
for GKAchievementViewController
http://developer.apple.com/library/ios/#documentation/GameKit/Reference/GKAchievementViewController_Ref/Reference/Reference.html

Resources