views:

1081

answers:

3

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?

+1  A: 

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

Tim
I am sorry, that is a typo. I am actually calling compareHighscore..
Wim Haanstra
A: 

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

CynicismRising
I am sorry, that is a typo. I am actually calling compareHighscore..
Wim Haanstra
+1  A: 

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.

Alex
This is obviously good general advice, but certainly wouldn't be the cause of this particular issue.
Jason Coco
How do you know that this is not the root cause of his issue?
Jonathan Arbogast
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.
Jason Coco
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?
Wim Haanstra
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.
Jason Coco
@ Jason, this was indeed the problem. I was reusing a HighScore object, which wasn't property reinitialized before the new round. Thank you very much for your answer.Pretty stupid bug, I feel very noobish now....
Wim Haanstra