I´m having a great deal of trouble with a bugg that in some cases gives the "initWithObjects:forKeys:count:]: attempt to insert nil object from objects[6]'" error message. It´s only occurring around every third trial and in the other cases it works fine. I haven´t debugged buggs that happeds at certain situations so that´s whyI´m asking for help. It might be difficult to find a solution but I would be glad to receive some advice atleast where to start look for the issue and how to debug it?
Basically my app have a method that sends a NSDictonary list with objects to a server. In some cases I want to remove an object if the user have´t chosen anything for that list. Problem is that the server died´t like sending an object with an empty space. So I made a kind of not nice looking work around. Basically The IBaction checks if the Object contains nil. If it contains nil it redirects to a very similar NSDictonary without the Object containing Nil. It woks in some cases but it seems like it sometimes don´t recognize the object containing nil.
Here´s the code in Inaction that redirects the code. I haven´t created a method for inserting anything to the object:#"DefaultCreateImageID" yet so as far as I know it should always be nil.
NSString *Imagestuff= [[NSUserDefaults standardUserDefaults] objectForKey:#"DefaultcreateImageID"];
if ( [[NSUserDefaults standardUserDefaults] objectForKey:#"DefaultcreateImageID"] != ( NSString *) [NSNull null] ){
DataHandler *handler = [DataHandler sharedDatahandler];
handler.authenticateUserDelegate = self;
[handler createActivityNoImage];
NSLog(Imagestuff);
}
else
{
DataHandler *handler = [DataHandler sharedDatahandler];
handler.authenticateUserDelegate = self;
[handler createActivity];
}
Thanks!
If you get an error "Trying to insert nil" then one of the objects you are trying to add to the dictionary is nil. Solution: Don't do that.
Figure out why some item you are trying to add to the dictionary is nil. Then figure out what you want to do in the situation.
To follow up on gnashers729 answer. The problem for me isn't nil but the fact my Inaction fails to reqognize what the object contains.
Here for example I tried to replace nil with a string to reqognize. I get the same problem that my method in some cases recognize the string and in some cases don´t.
NSString *Imagestuff= [[NSUserDefaults standardUserDefaults] objectForKey:#"DefaultcreateImageID"];
if ( [[NSUserDefaults standardUserDefaults] objectForKey:#"DefaultcreateImageID"] != ( NSString *) #"noImage" ){
Related
I see this issue has been asked a bit but all the answers seem to point to the cause being trying to update an object when the context has been deleted. I don't think I'm doing that but I'm getting the error so I'm confused (admittedly, I'm shaky on managing retention and references to begin with).
I have an Entity that holds user preferences as essentially key-value records. One of them is an email address.
UserPreference *prefEmailAddress;
#property (nonatomic, retain) UserPreference *prefEmailAddress;
In my class, in my ViewWillAppear method, I build a fetch request and get a reference to the email address value and set a UI text box to the value. This works fine.
NSArray *prefs = [context executeFetchRequest:request error: &error];
if ([prefs count] > 0) {
prefEmailAddress = [prefs objectAtIndex:0];
[prefEmailAddress setValue:emailAddress.text forKey:#"prefValue"];
}
However, in another method when I try to save the potentially modified text box text back to the object, I get the above crash.
I'm just doing this;
NSLog(#"Addr: %#",emailAddress.text);
// [prefEmailAddress setValue:emailAddress.text forKey:#"prefValue"];
The last line causes the exception. Seems like the prefEmailAddress object should still exist but it apparently doesn't.
Thanks for any hints on this.
I solved mine by removing
[fetchRequest setFetchBatchSize:<INT_VALUE>];
if this is in your code when fetching request.
Ok, I spent the last 8 hours fighting with it - it just seems beyond me. Here's my complete (relevant) code:
- (void)updateUserDefaults
{
NSMutableDictionary *viewControllerDetails = [[NSMutableDictionary alloc] initWithCapacity:4];
[viewControllerDetails setObject:[NSNumber numberWithInt:OOVenueClassControllerType] forKey:#"classType"];
[viewControllerDetails setObject:self.searchTerm forKey:#"searchTerm"];
[viewControllerDetails setObject:self.searchLocation forKey:#"searchLocation"];
//----- the next two lines cause the problem
NSString *res = [[NSString stringWithFormat:#"%#",[searchResults xmlString]] retain];
[viewControllerDetails setObject:res forKey:#"searchresults"];
//-----
NSMutableArray *viewControllersList = [NSMutableArray array] ;
[viewControllersList addObject:viewControllerDetails];
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
//the following line causes the error
[defs setObject:viewControllersList forKey:kViewControllersKey];
[defs synchronize];
[res release];
}
Note the block with the next two lines cause the problem. At first I didn't create another string, but added it later while trying to solve the problem.
If I comment out those two lines, everything works fine. If I put them back in, I get
- [CFString class]: message sent to deallocated instance 0xa1a9000
Is something is wrong with the string that I'm trying to put into the userdefaults? That string is rather large (about 200,000 characters), but I had stored even longer strings in user defaults in the past.
It's also worth noting that if I uninstall the app, then everything works fine. But on subsequent runs the problem exhibits itself.
So, how and why and where is the string getting deallocated? I have explicitly added retain - but that still doesn't help. What am I missing?
Edit: just realised I forgot to say that the error is thrown on line
[defs setObject:viewControllersList forKey:kViewControllersKey];
Also, for general information, method - (NSString *)xmlString on searchResults does exactly what the name means: creates an XML string with the information from that object.
Edit 2: I tried doing something else with that string - convert it to NSData, compress using zlib - but regardless of data type, that particular object gets deallocated. Does it have to do something with the size of the string?
NSString *res = [[NSString stringWithFormat:#"%#",[searchResults xmlString]] retain];
Is auto released. You don't need to release it at the end of your method. You are over-releasing it.
Further, you don't need to retain the [searchResults xmlString]. The stringWithFormat method already does it for you.
Good Luck!
Ok, not sure what exactly the problem was, but it was somewhere in the searchResults and/or xmlString method. searchResults object is originally created from XML received from the server (XML is parsed into the object structure). When xmlString was called, for some reason the string I was getting back was different from the original XML (I'm not talking about formatting, of course) - of 200,000 char-long string, within the first 500 chars or so there were some differences. I haven't been able to figure out why. So, instead of recreating the xml from object structure, I instead stored the original XML in a field in that object and, when xmlString was called, simply returned the original string. Now everything worked fine.
Thank you all for your support through this painful process.
EDIT Thanks to Matt's post I now understand that I should not be trying to access 'started' as an array. However, if that is the case, I would like to know why this code appears to be working in other places. It still seems to me that this should be "one-or-the-other." It should work or it shouldn't.
ORIGINAL
I'm using the same fetch request in various parts of my code to find the most recent game:
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:#"Game" withPredicate:#"started == started.#max"] anyObject];
'Game' is an NSManagedObject and 'started' is a date attribute. 'started' is set exactly once per object in awakeFromInsert. It is never changed after that. Game is never directly instantiated, but it has three subclasses. I have tried making Game both abstract and concrete, but neither has any effect on this problem.
I'm using an NSManagedObjectContext category to perform the fetch, as shown on cocoa with love here http://cocoawithlove.com/2008/03/core-data-one-line-fetch.html.
The error I am getting is the following:
Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. [<__NSDate 0xebb1130> valueForUndefinedKey:]: this class is not key value coding-compliant for the key #max. with userInfo {
NSTargetObjectUserInfoKey = "2010-11-06 11:16:53 GMT";
NSUnknownUserInfoKey = "#max";
}
It looks to me like the predicate might be trying to apply #max to a single NSDate, instead of all 'started' attributes in all games. I'm not sure though. I'm not very good with predicates, and it took me a lot of trial and error to make this one. I don't understand how the exact same fetch can have errors in different places, though.
The fetch is not part of an NSFetchedResultsController, but I am using a fetchedResultsController in the class where I'm getting the error. For example:
- (void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath{
Game *game = [self.frc objectAtIndexPath:indexPath];
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:#"Game" withPredicate:#"started == started.#max"] anyObject]; // Sometimes we get past this line, sometimes we don't...
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"EEE, MMM d, yyyy h:mm a"];
if (game != lastGame)
cell.detailTextLabel.text = [format stringFromDate:game.started];
else
cell.detailTextLabel.text = #"In Progress";
[format release];
...
}
and also here:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:#"Game" withPredicate:#"started == started.#max"] anyObject];
if (lastGame == [frc objectAtIndexPath:indexPath])
return NO;
return YES;
}
This exact fetch is performed several times in several places, for example on startup, but it only crashes in one class. As I said it is intermittent, but it seems to be sometime after I create a new Game object. The game is created in one tab, and the code above is from a second tab which shows history.
I have seen a similar error here. In that case the problem was solved by restarting the computer, which finally allowed XCode to realize that the attribute had been deleted from the model. I have tried that, and I'm still experiencing the problem. I have also tried deleting and recreating the 'started' attribute in the model. I have also read the Core Data Troubleshooting Guide, but was unable to find any help there either.
Predicates are applied to one source object at a time. If your source object does not have an array property, you can't use an array operator.
In your case, the predicate says:
Look at a given "Game". If its own
"started" property is equal to its own
"started" property with the #max KVC
array operator applied, then this
predicate will be true.
This is not what you want. The only situation where you'd use a KVC array operator in a predicate is where a property on an object is an array. e.g.
Fetch every "Season" where the "games.#max.homeTeamScore > 50" (i.e. seasons where a home team scored more than 50 in a game). This would work because the "games" property on a "Season" would be an array, so games.homeTeamScore would also be an array.
However, the "started" property on a single Game is not an array. The array you want to operate on is actually the array of all games, which is not a property of a game.
The only twisted way you could access the array of all games would be to fetch the array of all games first, then apply the array operator outside the predicate and then on the inside of the predicate only apply the equality test.
i.e. fetch all games first, then refetch with:
fetchObjectsForEntityName:#"Game" withPredicate:#"started == %#", [allGames valueForKey:#"#max.started"]
But this is not the smart thing to do either.
Ultimately, the correct way to fetch the game with the latest starting date as you're trying to do, can't be done with the single line fetch method.
You'll need to create a variant of the method that allows you to setSortDescriptors: on the fetch request (to sort by "started", descending) and then setFetchLimit:1 on the fetch request to only get first result.
Im reading the address book contacts... everything goes well until I test a contact with no
First Name ( Since I can create a contact with just an email or a phone or wathever....).
The code (reduced) is this:
- (NSMutableArray *) getContactsInfo {
NSMutableArray *contactsList = [[NSMutableArray alloc] init];
localAddressBook = ABAddressBookCreate();
int contactsLength = (int)ABAddressBookGetPersonCount(localAddressBook);
if (contactsLength < 1)
return nil;
for(int currentContact=1; currentContact < (contactsLength + 1); currentContact++) {
ABRecordRef person = ABAddressBookGetPersonWithRecordID(localAddressBook,(ABRecordID) currentContact);
firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSLog(#"%#", firstName);
[contactsList addObject:firstName];
CFRelease(person);
}
return contactsList;
}
and the output I get is this:
2010-02-15 14:16:25.616 testApp[7065:207] Contact0
2010-02-15 14:16:25.618 testApp[7065:207] Contact1
2010-02-15 14:16:25.619 testApp[7065:207] Contact2
Program received signal: “EXC_BAD_ACCESS”.
I have 3 contacts with First and Last names
And one created with just the last name, for test purposes.
It seems I can properly read any property such as email or address with arrays... but when a contact lacks First Name Property the app crashes.
You are doing something very wrong in your code: you are assuming that the record IDs are sequential and starting at 1. This is not the case at all, you cannot rely on this.
What you should do instead is use ABAddressBookCopyArrayOfAllPeople to find all records in the Address Book and then use the Core Foundation CFArray functions to get to the individual items.
(Yes, the Address Book API in the iPhone is terrible)
You may want to enable NSZombies to see exactly where the EXEC_BAD_ACCESS is coming from.
To make sure, the crash is taking place within ABRecordCopyValue and not when you try to use firstName for the first time (which may be NULL?) Also, person is not NULL either, correct? (In general more code in the question along with details about which line is crashing would be helpful.)
Another thing to try would be to cast person to an ABRecord* and use [valueForProperty][1]; the two types are toll-free bridged and you might get a different result out of the latter (though I doubt it).
Update: Given the code you have posted you need to check that firstName is not NULL before trying to output it via NSLog - it is very possible ABRecordCopyValue is simply returning NULL (representing the fact there is no first name data present for that record.) You should also check for the validity of the person ref value itself - passing NULL in person to ABRecordCopyValue could be the source of additional problems.
The problem is indeed a nil first name - but not at the log statement, rather where you try to insert nil into the array. You cannot insert a nil value into an array, that causes a crash. NSLog has not flushed output to the console yet which is why you do not yet see your last log statement saying first name is nil.
Any time you get data out of the address book, check to see if the value is nil before you insert it into anything.
Okay, I'm trying to write a high score function for my app.
My problem is that when no high score has been saved yet, my program crashes.
If I save it with:
[[NSUserDefaults standardUserDefaults] setObject:#"[given string]" forKey:#"firstName"];
first, it works fine. However, if I start up the program for the first time and try to view the high scores with the following code:
first = [[NSString alloc] initWithString:[[NSUserDefaults standardUserDefaults] objectForKey:#"firstName"]];
bad things happen.
Basically, is there away to see if nothing yet exist under firstName? Is there a way to initialize without erasing any name that might already be present?
Thanks.
The NSString documentation for initWithString: says
Parameters
aString
The string from which to copy characters. This value must not be nil.
The documentation for objectForKey: says
Return Value
The object associated with the
specified key, or nil if the key was
not found.
The problem seems to be that there is a nil returned when you try to retrieve firstName that doesn't exist yet and try to create a NSString with it as input.
The NSUserDefaults instance method registerDefaults: is meant for exactly this purpose: You can set default values for your preferences that will be overridden by any other value set for the same preference key. Just make sure to call it early enough that it will run before any code that needs to access your preferences.
You could load "first" like this:
first = [[[NSUserDefaults standardUserDefaults] objectForKey:#"firstName"] retain];
if (!first) {
// set default or do something else if there wasn't a value saved
first = #"N/A";
}