views:

103

answers:

3

My app won't save the data or load the data, it just crashes, I wonder what I'm doing wrong in my High Score Manager class.

I'm going to post my class's .h and .m file:

.h

#import <Foundation/Foundation.h>

@interface Score : NSObject
{
    NSString *name;
    NSNumber *score;
}

@property (assign, nonatomic) NSString *name;
@property (assign, nonatomic) NSNumber *score;

+ (Score *) score: (NSNumber *)score_ name: (NSString *)name_;
- (id) initWithScore: (NSNumber *)score_ name: (NSString *)name_;

@end

@interface HighScoreManager : NSObject
{
    NSArray *an_;
    NSArray *as_;
    BOOL loaded;
}

- (void) load;
- (BOOL) noScores;
- (NSArray *) sortedScores;
- (void) add: (NSString *)name score: (NSNumber *)score;

@end

.m

#import "HighScoreManager.h"

@implementation Score
@synthesize name, score;

+ (Score *) score: (NSNumber *)score_ name: (NSString *)name_
{
    return [[[Score alloc] initWithScore: score_ name: name_] autorelease];
}

- (id) initWithScore: (NSNumber *)score_ name: (NSString *)name_
{
    if((self = [super init]))
    {
        score = score_;
        name = name_;
    }

    return self;
}

@end

@implementation HighScoreManager

- (id) init
{
    if((self = [super init]))
    {
        loaded = NO;
    }

    return self;
}

- (void) load
{
    if(!loaded) {
        NSUserDefaults *NSUD = [NSUserDefaults standardUserDefaults];
        [NSUD synchronize];
        an_ = [NSUD arrayForKey: @"game.score.names"];
        as_ = [NSUD arrayForKey: @"game.score.scores"];
        [NSUD release];

        loaded = YES;
    }
}

- (BOOL) noScores
{
    [self load];
    return [an_ count] < 1;
}

- (NSArray *) sortedScores
{
    [self load];
    NSMutableArray *scoresObj = [NSMutableArray array];

    for(NSUInteger i = 0; i < [an_ count]; i++)
    {
        [scoresObj addObject: [Score score: [as_ objectAtIndex: i] name: [an_ objectAtIndex: i]]];
    }

    NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"score" ascending: NO] autorelease];
    NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

    return [scoresObj sortedArrayUsingDescriptors: sortDescriptors];
}

- (void) add: (NSString *)name score: (NSNumber *)score
{
    NSUserDefaults *NSUD2 = [NSUserDefaults standardUserDefaults];
    [NSUD2 setObject: [[NSUD2 arrayForKey: @"game.score.names"] arrayByAddingObject: name] forKey: @"game.score.names"];
    [NSUD2 setObject: [[NSUD2 arrayForKey: @"game.score.scores"] arrayByAddingObject: score] forKey: @"game.score.scores"];
    [NSUD2 synchronize];
}

- (void) dealloc
{
    [an_ release];
    [as_ release];
    [super dealloc];
}

@end

How I tried to use the class

    HighScoreManager *HSM1 = [HighScoreManager new];
    [HSM1 add: @"Johannes" score: [NSNumber numberWithInt: 1298]];
    [HSM1 add: @"Johannes" score: [NSNumber numberWithInt: 8723]];
    [HSM1 add: @"Johannes" score: [NSNumber numberWithInt: 3283]];
    [HSM1 add: @"Johannes" score: [NSNumber numberWithInt: 1763]];
    [HSM1 add: @"Johannes" score: [NSNumber numberWithInt: 9931]];

    HighScoreManager *HSM = [HighScoreManager new];

    // Check if there even are any high scores.
    if([HSM noScores])
    {
        CCLabel *noScoresYet = [CCLabel labelWithString: @"There are no scores yet." fontName: @"Helvetica" fontSize: 36];
        noScoresYet.position = ccp(win.width / 2, win.height / 2);
        [noScoresYet setColor: ccc3(0, 0, 0)];
        [self addChild: noScoresYet];
    } else
    {
        // Oh look, there were some high scores!

    }

    [HSM release];

Even though I "save" the scores, when I navigate away from the Scores page, and go back, it's where the app crashes. I'm not really sure what I'm doing wrong or why it isn't saving


I get this when it crashes "_class_getMethodNoSuper_nolock" and sometimes objC_send or something like that

A: 

Describe exactly where the crash is happening and maybe I can be more help. I spotted at least one issue:

return [[[self alloc] initWithScore: score_ name: name_] autorelease];

Should be

return [[[Score alloc] initWithScore: score_ name: name_] autorelease];
kubi
I updated it and added a little more to the question
Johannes Jensen
A: 

Didn't test your code but the first thing I noticed is your static factory methods, which tries to alloc self instead of the class Score

I'm pretty sure you need:

+ (Score *) score: (NSNumber *)score_ name: (NSString *)name_
{
     return [[[Score alloc] initWithScore: score_ name: name_] autorelease];
}

One more thing. Your properties in the Score class are declared as assign, which means you do not retain the score and name you get, if they go out of scope it will also crashes your app.

Ron Srebro
`[self alloc]` in a class method is idiomatic. `[Score alloc]` is unusual and sounds like a Javaism to me. A class should almost never mention itself by name in a method. You gain nothing and lose inheritance.
Chuck
I honestly didn't ever obj-c written like that or any other languages for that matter. I see your point but allocate is not an instance method - how can it be, the instance wasn't created yet. I always thougt that obj-c way of creating objects is strange.
Ron Srebro
+1  A: 
  • Do not release NSUD. You didn't create it and you didn't retain it, so you don't own it. This might be causing the crash.

  • You also should retain your instance variables.

  • [NSUD2 arrayForKey: @"game.score.names"] will return nil at the beginning, so [[NSUD2 arrayForKey: @"game.score.names"] arrayByAddingObject: name] will also be nil. You're always setting the dictionary values to nil.

  • (And avoid variable names like "an_". It makes your code difficult to read.)

nschum