0

For a little iPhone application I am making, I want to sort a NSMutableArray.

I found 2 ways of doing this, but they both result in the same thing. Sorting the array will cause some objects to 'overwrite' eachother.

First off, here is my code:

AppDelegate.h

NSMutableArray* highScores;

Somewhere down that AppDelegate.h, I also make this variable a property so that I can access it from differen classes:

@property (retain, nonatomic) NSMutableArray* highScores;

When my application starts, I read the high scores from a file and import them into my NSMutableArray.

AppDelegate.m

NSMutableData* data = [NSData dataWithContentsOfFile:highScoresPath];
NSKeyedUnarchiver* decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
self.highScores = [decoder decodeObjectForKey:@"highscoresArray"];

The objects I store in this NSMutableArray are from the type HighScore.

HighScore.h

@interface HighScore : NSObject {

    int score;
    int roundsPlayed;
    int wrongAnswers;

    NSString* name;

    NSDate* datetime;
}

@property int score;
@property int roundsPlayed;
@property int wrongAnswers;
@property (nonatomic, copy) NSDate* datetime;

@property (nonatomic, copy) NSString* name;

- (id) init;
- (void) update:(int)roundScore:(BOOL) correct;

@end

HighScore.m

#import "HighScore.h"

@implementation HighScore

@synthesize score, roundsPlayed, wrongAnswers, name, datetime;

- (id) init
{
    self.name = @"";
    self.score = 0;
    self.roundsPlayed = 0;
    self.wrongAnswers = 0;

    self.datetime = [NSDate date];

    return self;
}

- (void) update:(int)roundScore:(BOOL) correct
{
    self.score += roundScore;

    if (!correct)
        self.wrongAnswers++;

    self.roundsPlayed++;
    self.datetime = [NSDate date];
}

- (id) initWithCoder:(NSCoder *) decoder 
{   
    self.name = [[decoder decodeObjectForKey:@"name"] retain];
    self.score = [decoder decodeIntForKey:@"score"];
    self.roundsPlayed = [decoder decodeIntForKey:@"roundsPlayed"];
    self.wrongAnswers = [decoder decodeIntForKey:@"wrongAnswers"];
    self.datetime = [[decoder decodeObjectForKey:@"datetime"] retain];

    return self;
}

- (void) encodeWithCoder:(NSCoder *)encoder 
{
    [encoder encodeObject:self.name forKey:@"name"];
    [encoder encodeInt:self.score forKey:@"score"];
    [encoder encodeInt:self.roundsPlayed forKey:@"roundsPlayed"];
    [encoder encodeInt:self.wrongAnswers forKey:@"wrongAnswers"];
    [encoder encodeObject:self.datetime forKey:@"datetime"];
}

- (NSComparisonResult) compareHighscore:(HighScore*) h
{

    return [[NSNumber numberWithInt:self.score] compare:[NSNumber numberWithInt:h.score]];
}

@end

Now, when I try to sort my array by using the following code:

NSArray *sortedArray;
sortedArray = [highScores sortedArrayUsingSelector:@selector(compareHighscore:)];

It somehow screws up my highScores array, I get an X amound of highscores with the same score and name.

What am I doing wrong?

2
  • Are you sure that this is actually being caused by the call to sortedArrayUsingSelector? Did you try looking at the actual highScores array before and after? Is there something else somewhere in your code adding objects to your highScores array that might be inserting duplicate objects? Remember - it's not a set, so if you insert the same high scores object more than once, it will appear multiple times in the array but the score will always be the same since it's an object reference actually in the array. Commented Jun 8, 2009 at 21:31
  • I agree. I suggest you put a breakpoint on your NSArray *sortedArray; line just before the sot and then, in gdb print the array: po highScores Commented Jun 9, 2009 at 10:49

4 Answers 4

1

I'm noticing that in your initWithCoder: method, you're not doing this:

if (self = [super initWithCoder:coder]) {
    // Decode your stuff here
}

Same with your regular init method. There needs to be a call to [super init].

Also, since you defined your string properties as copy and you're using the property syntax, there's no need to retain them. They will be retained for you by the synthesized accessor.

Otherwise, your code looks fine to me. Just remember: every init method must always have a call to a super's init... method.

Sign up to request clarification or add additional context in comments.

6 Comments

This is obviously good general advice, but certainly wouldn't be the cause of this particular issue.
How do you know that this is not the root cause of his issue?
Because he's inheriting from NSObject. The cause is almost certainly that he's adding multiple references to the various score objects to the array in other places in his code.
There is one place in the application, in another view, I am adding a HighScore object to the highScores object in my AppDelegate. Is this wrong?
It's not necessarily wrong, but if you have the same object and add it more than once, it doesn't automatically make a copy, or a snapshot of the object when it inserts it into the array. It simply inserts another reference, so if you do this three times with three different scores, you will see three entries for the same person with the same score (whatever the current score property is on the object) in the array.
|
1

You're trying to sort using @selector(compare:), not @selector(compareHighscore:), which I presume was your intention.

Comments

0

try
sortedArray = [highScores sortedArrayUsingSelector:@selector( compareHighscore: )];

Comments

0

Post the actual compareHighscore: method. The most important thing is that it has to be consistent, that is if a <= b and b <= c, then a <= c and if a < b and b < c then a < c. If you managed to write a compare method that is not consistent, anything can happen.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.