【问题标题】:Objective-C NSUserDefaults: HighScoreManager, why doesn't this work?Objective-C NSUserDefaults:HighScoreManager,为什么这不起作用?
【发布时间】:2010-07-28 10:50:46
【问题描述】:

我的应用程序不会保存数据或加载数据,它只会崩溃,我想知道我在高分管理器课程中做错了什么。

我将发布我班级的 .h 和 .m 文件:

.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

我如何尝试使用该类

    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];

即使我“保存”了分数,但当我离开“分数”页面并返回时,应用程序就会崩溃。我不确定我做错了什么或为什么没有保存


当它崩溃“_class_getMethodNoSuper_nolock”,有时是 objC_send 或类似的东西时,我会得到这个

【问题讨论】:

  • 我现在的赌注是 Score 类中的 assign 属性(见我的答案)

标签: objective-c nsuserdefaults saving-data


【解决方案1】:
  • 不要释放NSUD。你没有创造它,也没有保留它,所以你不拥有它。这可能会导致崩溃。

  • 您还应该保留实例变量。

  • [NSUD2 arrayForKey: @"game.score.names"] 会在开头返回 nil,所以 [[NSUD2 arrayForKey: @"game.score.names"] arrayByAddingObject: name] 也将是 nil。您总是将字典值设置为 nil。

  • (并避免使用“an_”之类的变量名。这会使您的代码难以阅读。)

【讨论】:

    【解决方案2】:

    准确描述崩溃发生的位置,也许我可以提供更多帮助。我发现了至少一个问题:

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

    应该是

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

    【讨论】:

      【解决方案3】:

      没有测试您的代码,但我注意到的第一件事是您的静态工厂方法,它尝试分配 self 而不是类 Score

      我很确定你需要:

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

      还有一件事。您在 Score 类中的属性被声明为 assign,这意味着您不会保留您获得的分数和名称,如果它们超出范围也会导致您的应用崩溃。

      【讨论】:

      • [self alloc] 在类方法中是惯用的。 [Score alloc] 很不寻常,对我来说听起来像是 Java 主义。一个类几乎不应该在方法中通过名称提及自己。你一无所获,也失去了继承权。
      • 老实说,我从来没有像那样写过 obj-c 或任何其他语言。我明白你的意思,但 allocate 不是实例方法 - 怎么可能,实例尚未创建。我一直认为 obj-c 创建对象的方式很奇怪。
      猜你喜欢
      • 1970-01-01
      • 2018-11-05
      • 2020-07-01
      • 1970-01-01
      • 2012-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多