In my application I have a UITableView and some buttons that the user can click to sort the array to the order based upon some NSDate's or ints. So this is my method to try to sort my UITableView:
- (void)sortStats:(id)sender reloadData:(BOOL)dataBool {
NSSortDescriptor *descriptor = nil;
UIButton *clickedButton = (UIButton*)sender;
if (clickedButton.tag == 1) {
descriptor = [NSSortDescriptor sortDescriptorWithKey:#"Date" ascending:NO];
}
[self.cellArray sortUsingDescriptors:[NSArray arrayWithObject:descriptor]];
[[NSUserDefaults standardUserDefaults] setObject:self.cellArray forKey:#"cellArray"];
if (dataBool) {
[ivstatstableView reloadData];
}
[ivstatstableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
}
So originally I just had this method without the reloadData parameter because it seemed that reloadData on the UITableView was causing the crash.
This is what the console crash log is:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'
Anyway is there any code here that would be causing this crash? I really want to get this functionality working in my app and I know I am close to fixing it but I am just not sure whats causing this issue.
Any ideas?
There is at least one place where this could be happening, and perhaps others. In the code where you get the contents of the user defaults, you don't check for nil. So instead of this:
[self.cellArray addObjectsFromArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"array"]];
you might want to try this:
NSArray *defaultCellArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"array"];
if (defaultCellArray) {
[self.cellArray addObjectsFromArray:defaultCellArray];
}
It is also possible that the initWithObjects call that is failing (according to your error message) is nested within another call, perhaps in this call:
[self.cellArray sortUsingDescriptors:[NSArray arrayWithObject:descriptor]];
If you look at the full call stack it would tell you if this call is making subsequent calls to initWithObjects and possibly passing it a nil. In your case, for example, you would pass in a nil yo the array you are creating if clickedButton.tag has not yet been set to a value of 1 or 2. You might want to add an additional else clause to help diagnose the problem:
if (clickedButton.tag == 1) {
descriptor = [NSSortDescriptor sortDescriptorWithKey:#"Date" ascending:NO];
} else if (clickedButton.tag == 2) {
descriptor = [NSSortDescriptor sortDescriptorWithKey:#"Score" ascending:NO];
} else {
NSLog(#"Unexpected error: Can't determine sort descriptor");
}
This is all pretty complicated, but one thing sticks out:
[[NSUserDefaults standardUserDefaults] setObject:self.cellArray
forKey:#"cellArray"];
I think you should change that to this:
NSArray *array = [NSArray arrayWithArray:self.cellArray];
[[NSUserDefaults standardUserDefaults] setObject:array forKey:#"cellArray"];
Secondly, add asserts() after every place where you think you should have an object, i.e.:
UIButton *theButton = ...
assert(theButton);
You also say that the number of rows is double the cellArray count, guess thats intentional.
Related
as the title says I'm having an issue with taking objects out of an array, flipping them, and putting them back in. Below is the code I currently have that ends in this error
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI removeObjectsAtIndexes:]: unrecognized selector sent to instance
I was wondering if anyone knew how to fix this? Here's a little more info on how I have it set up:
The object "PEG" is an NSString that displays "-0.6", "4.36"
GlobalSortedArray is an array filled with dictionary containing the PEG object
//Declare variables
NSMutableArray *negArray = [[NSMutableArray alloc]init];
NSMutableIndexSet *index = [[NSMutableIndexSet alloc]init];
int negcount = 0;
NSDictionary *forLoopDict;
for (forLoopDict in globalSortedArray)
{
if ([[forLoopDict objectForKey:#"PEG"] hasPrefix:#"-"])
{
[index addIndex:negcount];
}
negcount++;
}
NSLog(#"%#", negArray);
// Removes objects from main array. This is what seems to be messing up.
[globalSortedArray removeObjectsAtIndexes:index];
// Reverses the array
NSArray* reversedArray = [[negArray reverseObjectEnumerator] allObjects];
// insters them back into the main array
[globalSortedArray insertObjects:negArray atIndexes:0];
You are trying to remove an item from globalSortedArray. It is an NSArray and not mutable.
globalSortedArray as NSmutableArray
NSArray -- > NSMutableArray
I have found the Error Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object' when i add object to mutable array at second time first time added successfully but second time it is crash the app i think there is problem with when i added object to array.
Below code is crash.
- (void) viewWillAppear:(BOOL)animated
{
if ([defaults objectForKey:#"Groups"] != nil)
{
NSLog(#"not nil defaults.");
arrGroups = (NSMutableArray *)[defaults objectForKey:#"Groups"];
}
else
{
NSLog(#"nil defaults.");
arrGroups = [[NSMutableArray alloc] init];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(#"button index == %ld",(long)buttonIndex);
//txtCategory = [[alertView textFieldAtIndex:0] text];
if (buttonIndex == 1)
{
//[self addingCategory:self];
NSLog(#"Adding Group name = %#",[[alertView textFieldAtIndex:0]text]);
[arrGroups addObject:[[alertView textFieldAtIndex:0]text]]; **//Crash here! at the time of add second object or also when i remove first object**
NSLog(#"Added to array.");
[defaults setObject:arrGroups forKey:#"Groups"];
[defaults synchronize];
//[defaults release];
[tblGroups reloadData];
}
}
when i remove first object at that time i replace the userdefault with updated array so there is no problem i think. and i did not found proper reason for that crash.
so please support me either understood me the problem or solution but without understand the problem i can't understood solution so please any one tell that why this happen.
Thanks.
The problem with assigning to a NSMutableArray is, it will only work if defaultDefects was assigned an NSMutableArray for the given key.
Note: NSUserDefaults always returns an immutable object.
Do this instead
NSMutableArray *arrGroups = [[defaults objectForKey:#"Groups"]mutableCopy];
this guarantees a mutable copy.
Another way is.
arrGroups = [[NSMutableArray alloc]initWithArray:[defaults objectForKey:#"Groups"]]; //in your viewWillAppear where you assign array from defaults.
I have a UIPickerView that I am trying populate with the results from a NSFetchRequest pulling data from a managedObjectContext. When I initialize my UIPickerView with the following, KCModalPickerView *pickerView = [[KCModalPickerView alloc] initWithValues:_userNames]; Xcode doesn't throw and warnings or errors, but when I build and run the app I am getting the following error.
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Account copyWithZone:]: unrecognized selector sent to instance 0x7a60ec70'
* First throw call stack:
Now before you say this error is due to me not implementing the copyWithZone method in my vc, I want to point out that nowhere in my class files am I using the keyword copy
The method that I was told that is causinging the crash belongs to the KCModalPicker class implementation file. And the method looks like the following,
// edit this method
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [self.values objectAtIndex:row];
}
What do I need to change / edit / add to prevent this app from crashing?
Update
_usernames is a NSArray ...the results look like the following,
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Account" inManagedObjectContext:_managedObjectContext];
[fetchRequest setEntity:entity];
fetchRequest.propertiesToFetch = [NSArray arrayWithObject:[[entity propertiesByName] objectForKey:#"username"]];
NSError *error = nil;
NSArray _usernames = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
KCModalPickerView expects an array of NSString, you give it an array of Account. The framework tries to copy your instance because it thinks it's an NSString, which conforms to the NSCopying protocol and implements copyWithZone:. Your object does not, and there will be a [Account copyWithZone:]: unrecognized selector sent to instance exception.
Simply create an array of NSStrings by using the appropriate attribute from your Core Data object.
There are probably smarter ways for this, but this would be the obvious solution:
NSMutableArray *names = [NSMutableArray arrayWithCapacity:[_usernames count]];
for (Account *account in _usernames) {
NSString *accountName = account.name;
if (!accountName) {
accountName = #"<Unknown Account>";
}
[names addObject:accountName];
}
KCModalPickerView *pickerView = [[KCModalPickerView alloc] initWithValues:names];
I just saw that you have set propertiesToFetch. Additionally you have to set resultsType of the fetchRequest to NSDictionaryResultType. In this case executeFetchRequest:error: returns an array of dictionaries. And you should be able to use NSArray *names = [_usernames valueForKey:#"username"]; instead of the for loop.
Inside a method, I have:
[self makeRequestToServerForVehicles:self.load.loadId successBlock:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
Info *info = mappingResult.array[0];
self.load.bagOne = info.firstArray;
self.load.bagTwo = info.secondArray;
self.load.itemsNeeded = [self itemsFromBagTwo]; <---- App crashes here
- (NSArray *)itemsFromBagTwo{
NSMutableArray *items = [[NSMutableArray alloc] init];
for (Group *group in self.load.bagTwo) {
[items addObjectsFromArray:group.items];
}
return items;
}
When I run this, the app crashes with this error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'setObjectForKey: key cannot be nil'
When I NSLog the array that is returned, it does not come back nil. It comes back with the items that it needs to come back with.
If I do this,
NSArray *items = [self itemsFromBagTwo]; <--- Doesn't crash
I am not sure what is wrong, any help would be greatly appreciated.
The error makes it sound like the compiler is interpreting self.load.itemsNeeded using key value coding instead of getter and setter methods.
Try rewriting your code as
[[self load] setItemsNeeded: [self itemsFromBagTwo] ];
And see what happens. (That code does explicit method calls rather than ambiguous code that might invoke a getter and a setter, might reference items in a struct, or might compile as key-value coding.)
The following method:
- (NSMutableArray*) timeSortedBegins {
NSMutableArray* begins = [self.spans valueForKey: #"begin"];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey: #"cycleOffsetObject" ascending: YES];
[begins sortUsingDescriptors: #[sort]];
return begins;
}
throws this runtime exception:
2014-03-21 14:41:32.482 myValve[1741:60b] -[__NSArrayI sortUsingDescriptors:]: unrecognized selector sent to instance 0x16d7bc20
2014-03-21 14:41:32.484 myValve[1741:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI sortUsingDescriptors:]: unrecognized selector sent to instance 0x16d7bc20'
I have used breakpoints to convince myself that the begins array is indeed full of (two in this case) WEAnchor* objects. And that object implements the following two methods:
- (NSTimeInterval) cycleOffset {
return self.offset + (self.datum ? self.datum.cycleOffset : 0.0);
}
- (NSNumber*) cycleOffsetObject {
return [NSNumber numberWithDouble: self.cycleOffset];
}
To be honest, I only added the cycleOffsetObject wrapper method, because I thought maybe it couldn't work with non object values, I was using initWithKey: #"cycleOffset" before that. I have not declared these in the header file as a property, they're just accessor methods, not state. Is that the problem? If it is, how do you sort by the return value of a given selector? Or is it something head smackingly obvious that I'm just missing?
As #dtrotzjr says, it sounds like your array is an immutable, not a mutable array.
You can either use mutableCopy to create a mutable copy and then sort that copy, or use the NSArray method sortedArrayUsingDescriptors: (which operates on an immutable array, and returns a sorted version of the contents as a second immutable array.)
To use mutableCopy, your code might look like this:
- (NSMutableArray*) timeSortedBegins {
NSMutableArray* begins = [[self.spans valueForKey: #"begin"] mutableCopy];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey: #"cycleOffsetObject" ascending: YES];
[begins sortUsingDescriptors: #[sort]];
return begins;
}
Check that [self.spans valueForKey: #"begin"] is actually an NSMutableArray before casting it. The error message indicates that the pointer is actually an NSArray