sortUsingSelector Not Sorting an NSStrings Array
This is confusing to me. I have a function that does this:
void ListAllStoredLocations(NSString *SearchTerm){
NSMutableDictionary *item;
NSString* filePath = [[NSSearchPathForDirect开发者_StackOverfloworiesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingString:@"/Preferences/yourprogram.plist"];
item = [[[NSMutableDictionary alloc] initWithContentsOfFile:filePath] mutableCopy];
NSMutableArray *ReadStoredArray = [item objectForKey:SearchTerm];
NSMutableArray *SortedArray = [[NSMutableArray alloc] init];
NSString *CurrentResult=@"";
for (int i = 0; i< [ReadStoredArray count]; i++){
CurrentResult=(NSString *)[ReadStoredArray objectAtIndex:i];
[SortedArray addObject:CurrentResult];
}
[SortedArray sortUsingSelector:@selector(compare:)];
for (int i = 0; i< [SortedArray count]; i++){
NSLog(@"%@",[SortedArray objectAtIndex:i]);
}
[item release];
}
Which finds outputs NSStrings in the first for loop like this:
Location1
Location2
Not a location
Location2
Location3
Location2
and I want the output to be alphabetical:
Location1
Location2
Location2
Location2
Location3
Not a location
But, no matter what, the "[SortedArray sortUsingSelector:@selector(compare:)];" just does not sort the array. Nothing happens.
Maybe I'm going about this all wrong, but every example that I've seen online sorts NSStrings like this - so I don't know what to do.
My endgame, if there is a better solution out there is to output the count of the greatest repeated entry. I was thinking that sorting would be a step in that direction.
Really, what I'm looking for is this as output:
Location2
Because "location2" has the most duplications in that list.
Any help?
Given your array of string looks like this:
NSMutableArray * array = [NSMutableArray array];
[array addObject:@"Location1"];
[array addObject:@"Location2"];
[array addObject:@"Not a location"];
[array addObject:@"Location2"];
[array addObject:@"Location3"];
[array addObject:@"Location2"];
NSLog(@"------------- original:");
for (id obj in array) NSLog(@"%@", obj);
You can sort it like this:
NSLog(@"------------- sorted:");
NSArray * sortedArray =
[array sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
for (id obj in sortedArray) NSLog(@"%@", obj);
Output:
2010-02-06 00:24:14.915 x[23867:903] ------------- original:
2010-02-06 00:24:14.917 x[23867:903] Location1
2010-02-06 00:24:14.921 x[23867:903] Location2
2010-02-06 00:24:14.922 x[23867:903] Not a location
2010-02-06 00:24:14.922 x[23867:903] Location2
2010-02-06 00:24:14.923 x[23867:903] Location3
2010-02-06 00:24:14.924 x[23867:903] Location2
2010-02-06 00:24:14.924 x[23867:903] ------------- sorted:
2010-02-06 00:24:14.925 x[23867:903] Location1
2010-02-06 00:24:14.926 x[23867:903] Location2
2010-02-06 00:24:14.926 x[23867:903] Location2
2010-02-06 00:24:14.927 x[23867:903] Location2
2010-02-06 00:24:14.927 x[23867:903] Location3
2010-02-06 00:24:14.928 x[23867:903] Not a location
If you want to find the object with the most occurrences, given the original array:
NSCountedSet * set = [[NSCountedSet alloc] initWithArray:array];
for (id obj in set) NSLog(@"%d - %@", [set countForObject:obj], obj);
int count = 0;
int maxc = 0;
id maxobj;
for (id obj in set)
{
count = [set countForObject:obj];
if (maxc < count) maxc = count, maxobj = obj;
}
NSLog(@"max is: %d - %@", maxc, maxobj);
Output:
2010-02-06 00:39:46.310 x[24516:903] 1 - Location1
2010-02-06 00:39:46.311 x[24516:903] 1 - Not a location
2010-02-06 00:39:46.311 x[24516:903] 3 - Location2
2010-02-06 00:39:46.312 x[24516:903] 1 - Location3
2010-02-06 00:39:46.313 x[24516:903] max is: 3 - Location2
To start, you are leaking memory like crazy. Learn the rules: if you create an object (alloc/init or copy) then you own it and must release it.
item = [[[NSMutableDictionary alloc] initWithContentsOfFile:filePath] mutableCopy];
In that line you are creating a mutable dictionary, then creating a mutable copy of it, losing the original instance. You should replace that with:
item = [[NSDictionary alloc] initWithContentsOfFile:filePath];
You don't actually mutate the dictionary in your code, so I let it be NSDictionary.
Next, the type on this declaration:
NSMutableArray *ReadStoredArray = [item objectForKey:SearchTerm];
is incorrect. Even if the dictionary was mutable, it's members are not guaranteed to be. (mutableCopy
is a shallow copy.) Since you don't actually modify that array, let's change the line to:
NSArray *ReadStoredArray = [item objectForKey:SearchTerm];
Now, if you want to copy items from ReadStoredArray into SortedArray, you could replace the loop with
[SortedArray addObjectsFromArray:ReadStoredArray];
But since you're making an exact copy, you could also just write
SortedArray = [ReadStoredArray mutableCopy];
But you don't seem to need SortedArray
to be mutable, so you could just call this other form, which returns a new sorted array rather than sorting a mutable array in place:
SortedArray = [ReadStoredArray sortedArrayUsingSelector:@selector(compare:)];
So now your function looks like this:
void ListAllStoredLocations(NSString *SearchTerm) {
NSDictionary *item;
NSString* filePath = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingString:@"/Preferences/yourprogram.plist"];
item = [[NSDictionary alloc] initWithContentsOfFile:filePath];
NSArray *ReadStoredArray = [item objectForKey:SearchTerm];
NSArray *SortedArray = [ReadStoredArray sortedArrayUsingSelector:@selector(compare:)];
for (int i = 0; i< [SortedArray count]; i++){
NSLog(@"%@",[SortedArray objectAtIndex:i]);
}
[item release];
}
You don't need to release ReadStoredArray
or SortedArray
because you do not own them (no alloc/init or copy in the calls).
As for your actual question... there's no obvious reason from the code why the sorting would not work. Sorry! A lot of common problems would have triggered exceptions, not silent failures.
If the file did not exist or could not be loaded, initWithContentsOfFile:
would have thrown an exception. If ReadStoredArray
was nil, then CurrentResult
would be nil, and addObject:
would throw an exception. If the objects in the array did not respond to the compare:
selector, sortUsingSelector:
would have thrown an exception. If SortedArray
was nil, the code would silently fail, but it would also print no output. (Also, for it to be nil the alloc/init would have to fail, meaning you were out of memory.)
Aside from memory leaks and nontraditional style (starting your variable names with upper case letters) there's nothing apparently wrong with your code. Something is missing.
You can easily sort an array using the API:
[YourArrayObj sortUsingSelector:@selector(compare:)];
After this statement you just print your array objects you'll get the sorted array.
I didn't see anything obvious that would prevent your array from sorting, so I would try using a custom myCompare: method as the sorting selector instead of the built-in compare. This will allow you to log each individual comparison, so you know each object is getting compared as it should, and it's returning the correct comparison result.
Add this to your file (above your function definition), then change your function to sort with @selector(myCompare:):
@interface NSString (MyCompare)
- (NSComparisonResult) myCompare: (NSString *) aString;
@end
@implementation NSString (MyCompare)
- (NSComparisonResult) myCompare: (NSString *) aString
{
NSComparisonResult result;
result = [self compare: aString];
NSLog(@"Compared %@ & %@, result: %d", self, aString, (int) result);
return result;
}
@end
One little gotcha with sorting arrays is that you have to look to see if an array is being returned in the sorting process. If you neglect to catch the returned array it might seem like the array is not being sorted. It probably is, but as soon as it is, if there is no array to catch it, it'll be gone again.
精彩评论