I have a NSMutableArray that has a inner NSMutableArray that I would like to sort (sort the outer items) by a date property within the inner NSMutableArray.
The array looks like this
[
{
messages : [
{
date
},
..... etc
]
},
..... etc
]
The code below is my attempt that throws an exception
NSSortDescriptor *sdSortDate = [NSSortDescriptor sortDescriptorWithKey:#"messages.#lastObject.date" ascending:YES];
events = [NSMutableArray arrayWithArray:[events sortedArrayUsingDescriptors:#[sdSortDate]]];
example
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '[<__NSArrayM 0x604000654670> valueForKeyPath:]: this class does not implement the lastObject operation.'
Any ideas on how I can do this?
You should use messages.date.#lastObject instead of messages.#lastObject.date. Try the code below
NSSortDescriptor *sdSortDate = [NSSortDescriptor sortDescriptorWithKey:#"messages.date.#lastObject" ascending:YES];
events = [NSMutableArray arrayWithArray:[events sortedArrayUsingDescriptors:#[sdSortDate]]];
Related
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
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFConstantString 0xa2f4> valueForUndefinedKey:]: this class is not key value coding-compliant for the key name.'
agesArray=[NSMutableArray array];
sortDescriptor *a=[[sortDescriptor alloc]init];
a.name=#"SAS";
a.lastname=#"kumar";
[agesArray addObject:a.name];
sortDescriptor *a1=[[sortDescriptor alloc]init];
a1.name=#"DAMAN";
[agesArray addObject:a1.name];
sortDescriptor *a11=[[sortDescriptor alloc]init];
a11.name=#"AKSHAY";
[agesArray addObject:a11.name];
NSSortDescriptor *sortDesc = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(compare:)];
[agesArray sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];
Your agesArray contains NSString objects.
[agesArray addObject:a.name]; //see you are adding string here
NSString class does not contain a property called name. So it is crashing.
Probably you may want to do something like
[agesArray addObject:a];
Side note : Give meaningful name to objects/Methods or whatever. Objective C demand it. Don`t use a,a1,a11
I am trying to sort an NSMutableArray with the following structure:
(
{
Code = "390954-150";
Size = "35";
},
{
Code = 790540MSO;
Size = "30";
}
)
I am trying to sort basing on the Code value, the NSMutableArray is called arrayProduct:
//Sort array by Code
NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Code" ascending:YES];
[arrayProduct sortUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
//
However the above code throws the following exception:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray replaceObjectAtIndex:withObject:]: mutating method sent to immutable object'
Your arrayProduct looks to be NSArray.
Try converting it into NSMutableArray and :
NSMutableArray *mutableProducts = [NSMutableArray arrayWithArray:arrayProduct];
[mutableProducts sortUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
I have a Table View Controller with a list of Formations handled by a fetchResultsController.
Here's how my core data entities looks like :
I try to sort my fetchResultsController by dateRangelike this :
// |fetchedResultsController| custom setter
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:self.fetchRequest managedObjectContext:self.mainManagedObjectContext sectionNameKeyPath:#"dateRange" cacheName:kFormationsFetchedCacheName];
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
// |fetchRequest| custom setter
- (NSFetchRequest *)fetchRequest {
if (_fetchRequest != nil) {
return _fetchRequest;
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"student == %#", self.currentStudent];
NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"dateRange" ascending:NO];
NSSortDescriptor *nameDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:NO];
_fetchRequest = [[NSFetchRequest alloc] initWithEntityName:kBSFormation];
_fetchRequest.predicate = predicate;
_fetchRequest.sortDescriptors = [NSArray arrayWithObjects: dateDescriptor, nameDescriptor, nil];
return _fetchRequest;
}
Everything is fine when i try to add the very first Formation, but for the next ones, i have these errors:
2013-01-30 22:43:08.370 [7202:c07] -[BSDateRange compare:]: unrecognized selector sent to instance 0x81781a0
2013-01-30 22:43:08.371 [7202:c07] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[BSDateRange compare:]: unrecognized selector sent to instance 0x81781a0 with userInfo (null)
2013-01-30 22:43:08.372 [7202:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[BSDateRange compare:]: unrecognized selector sent to instance 0x81781a0'
If i comment this line : NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"dateRange" ascending:NO];, it's working but my table view is messy as the sectionNameKeyPath is set to dateRange
Someone is figuring out what's the problem here ? :/
You're telling it to sort based on the dateRange relationship. But dateRange is a relationship to BSDateRange, and how does Core Data compare those? Should it use from, or maybe to, or some combination of those? You can't just tell it to sort on an object like that, because it's not obvious how sorting should work.
Instead, first figure out what sorting even means. Then modify your sort descriptor appropriately. For example if you decide that sorting depends on the from value, change the sort descriptor to use the key path to from:
NSSortDescriptor *dateDescriptor = [NSSortDescriptor
sortDescriptorWithKey:#"dateRange.from"
ascending:NO];
If you need to sort based on both from and to, use more than one sort descriptor.
I have an array of NSDictionnary and I would like to sort them by an int value (the key is named "age").
For exemple :
Dic1 : age = 30, sex = male;
Dic2 : age = 24, sex = male;
Array : Dic1, Dic2;
Now with a compare method I would lik to have :
Array : Dic2, Dic1;
I tried lots of things but doesn't work. I as using NSSortDescriptor but it's only available since iOS 4.0 :(
Have you got a solution ?
Thanks !
EDIT :
I wrote a compare method on NSDictionary category :
- (NSComparisonResult)compareGood:(NSDictionary *)otherObject
{
return [[self objectForKey:#"age"] compare:[otherObject objectForKey:#"age"]];
}
But I have this crash error : Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSCFNumber compare:]: nil argument'
The documentation for NSSortDescriptor says:
Available in iOS 2.0 and later.
Likewise for the NSMutableArray method -sortUsingDescriptors:. You should be able to do this:
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"age"
ascending:YES]
autorelease];
[myArray sortUsingDescriptors:[NSArray arrayWithObject:descriptor];
or, if myArray isn't mutable, do this for the second line:
NSArray *sortedArray = [myArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];