使用 NSCoder 初始化静态单例对象

发布于 2024-12-28 03:43:04 字数 2587 浏览 1 评论 0原文

我正在开发一个 iPhone 应用程序,并且在共享单例类方面遇到了一些麻烦。 我使用共享单例来存储两个变量 int gameRunsint totalScore 每次用户加载应用程序时,“gamRuns”都会递增,并且“totalScore”很明显:D

问题如下,当使用此代码加载应用程序时,我使用自己的方法加载单例和初始化:

+ (SingletonLevelState*)sharedLevelStateInstance {

static SingletonLevelState *sharedLevelStateInstance;

@synchronized(self) {
    if(!sharedLevelStateInstance) {
        //Init a singleton
        sharedLevelStateInstance = [[SingletonLevelState alloc] init];
        sharedLevelStateInstance->gameRuns = 1;
        sharedLevelStateInstance->totalScore = 0;
    }
}
return sharedLevelStateInstance;
}

这工作得很好,因为我可以从任何其他类引用此类,并且始终获取指向同一对象的指针,因此这对于其他对象来说效果很好:

sharedLevelState = [SingletonLevelState sharedLevelStateInstance];
sharedLevelStateInstance.gameRuns++;

现在我添加了 NSCoder 协议,并添加了两个方法 initWithCoderencodeWithCoder 如下:

- (void) encodeWithCoder: (NSCoder *)coder
{
    //encode level data
    [coder encodeInt:self->gameRuns forKey:@"gameRuns"];
    [coder encodeInt:self->totalScore forKey:@"totalScore"];
}
- (id) initWithCoder: (NSCoder *) coder
{
    if(self = [super init]){
        self->gameRuns = [coder decodeIntForKey:@"gameRuns"];
        self->totalScore = [coder decodeIntForKey:@"totalScore"];
    }
    return self;
}

现在,当应用程序加载时,我检查是否已经保存了状态,如果存在,我只需使用该文件取消归档该类,如果没有,我使用以下命令初始化该类我上面的自定义方法,然后设置其默认值,将其编码到文件中,以便我们有一个保存的状态,代码如下:

 //Load Level state
sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];

//Check if file is saved
NSFileManager *fm = [[NSFileManager alloc] init];
NSString *gameStatePath = [NSString stringWithString:[self getSavePath]];

if([fm fileExistsAtPath:gameStatePath]){
    [self loadState];
    sharedLevelStateInstance.gameRuns = sharedLevelStateInstance.gameRuns+1;
    NSLog(@"Loaded %d times", [sharedLevelStateInstance gameRuns]);
}
[fm release];

现在 if 语句中的最后一行完美运行,每次我按预期加载应用程序时它都会递增 我真的感觉快乐哈哈。

但是,当我尝试通过执行以下操作来获取另一个类中单例的引用时,问题就出现了:

sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];
NSLog(@"Played: %d times", sharedLevelStateInstance.gameRuns);

它总是倒数到 1,我知道会发生什么,但我不起诉什么是最好的解决这个问题的方法是,当我 initWithCoder 单例时,它不会返回静态对象,而是创建一个新对象,当我初始化我的 sharedLevelStateInstance 时,它会调用我的第一个自定义对象方法,将其初始化为硬编码的默认值。

StackOverflow,你能帮帮我吗?!

我只需要知道获取对同一对象的引用的最佳方法是什么,而无需每次 initWithCoder 都分配一个新对象!

谢谢 :)

I'm working on an iPhone app and facing some troubles with my shared singleton class.
I'm using a shared singleton to store two variables
int gameRuns and int totalScore
'gamRuns' just increments every time the user loads the app, and 'totalScore' is obvious :D

the issue is as follows, I load the singleton and init using my own method when the app loads using this code:

+ (SingletonLevelState*)sharedLevelStateInstance {

static SingletonLevelState *sharedLevelStateInstance;

@synchronized(self) {
    if(!sharedLevelStateInstance) {
        //Init a singleton
        sharedLevelStateInstance = [[SingletonLevelState alloc] init];
        sharedLevelStateInstance->gameRuns = 1;
        sharedLevelStateInstance->totalScore = 0;
    }
}
return sharedLevelStateInstance;
}

This is working great as I can reference this class from any other class and always get a pointer to the same object, so this works fine from other objects:

sharedLevelState = [SingletonLevelState sharedLevelStateInstance];
sharedLevelStateInstance.gameRuns++;

Now I added the NSCoder protocol, and added the two methods initWithCoder and encodeWithCoder as follows :

- (void) encodeWithCoder: (NSCoder *)coder
{
    //encode level data
    [coder encodeInt:self->gameRuns forKey:@"gameRuns"];
    [coder encodeInt:self->totalScore forKey:@"totalScore"];
}
- (id) initWithCoder: (NSCoder *) coder
{
    if(self = [super init]){
        self->gameRuns = [coder decodeIntForKey:@"gameRuns"];
        self->totalScore = [coder decodeIntForKey:@"totalScore"];
    }
    return self;
}

Now when the app loads, I check to see if we already have a saved sate, if it exists, I just unarchive the class with that file, if not, I init that class using my custom method above, then set its defaults, encode it to file so we have a saved state, here's the code:

 //Load Level state
sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];

//Check if file is saved
NSFileManager *fm = [[NSFileManager alloc] init];
NSString *gameStatePath = [NSString stringWithString:[self getSavePath]];

if([fm fileExistsAtPath:gameStatePath]){
    [self loadState];
    sharedLevelStateInstance.gameRuns = sharedLevelStateInstance.gameRuns+1;
    NSLog(@"Loaded %d times", [sharedLevelStateInstance gameRuns]);
}
[fm release];

Now the last line in the if statement works perfectly, it increments every time I load the app as expected and I feel really happy lol.

However, the problem arises when I try to get a reference of the singleton in another class by doing the following:

sharedLevelStateInstance = [SingletonLevelState sharedLevelStateInstance];
NSLog(@"Played: %d times", sharedLevelStateInstance.gameRuns);

It always counts back to 1, I know what happens but I'm not sue what's the best way to solve it, when I initWithCoder the singleton, It's not returning a static object, it creates a new one, when I init my sharedLevelStateInstance, it calls my first custom method, initializing it to the defaults hardcoded.

So StackOverflow, can you please help me ?!

I just need to know what's the best way to get a reference to the same object without allocating a new one every time I initWithCoder !

Thanks :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

So尛奶瓶 2025-01-04 03:43:04

因此,您的代码可能应该如下所示:

if(self = [[SingletonLevelState sharedLevelStateInstance] retain])

设置单例的变量,并返回单例。请务必保留单例,以便当 NSCoder 释放此实例时,它不会完全释放您的单例。

So, you code should probably look like this:

if(self = [[SingletonLevelState sharedLevelStateInstance] retain])

Which sets the variables of the singleton, and returns the singleton. Be sure to retain the singleton, so that when the NSCoder releases this instance, it doesn't fully deallocate your singleton.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文