1

我创建了一个简单的单例类来保存我的项目的静态数据。我第一次访问这个单例是在我的 Cocos2d 场景中的 onEnter 方法。但是,当我稍后尝试以另一种方法(相同场景)再次访问它时,这个单例已经被释放。我很困惑,如何防止我的单身人士被释放?

这是我的单身人士的界面部分:

#import <Foundation/Foundation.h>

@interface OrchestraData : NSObject
+(OrchestraData *)sharedOrchestraData;
@property (retain, readonly) NSArray *animalNames;
@end

执行:

#import "OrchestraData.h"

@implementation OrchestraData
@synthesize animalNames = animalNames_;

+(OrchestraData*)sharedOrchestraData
{
    static dispatch_once_t pred;
    static OrchestraData *_sharedOrchestraData = nil;

    dispatch_once(&pred, ^{ _sharedOrchestraData = [[OrchestraData alloc] init]; });
    return _sharedOrchestraData;
}

-(id)init {
    if (self = [super init]) {
        animalNames_ = [NSArray arrayWithObjects:@"giraffe", @"giraffe", @"giraffe", @"giraffe", nil];
    }
    return self;
}
@end

我以这种方式使用我的单身人士:

[[OrchestraData sharedOrchestraData] animalNames];

更新:我在启用 NSZombies 的情况下重新审视了它,看起来好像我的 NSArrays 被释放了,而不是单例本身。我该怎么办?

4

4 回答 4

4

您必须以这种方式实现您的单例:

1)在你的单例类的 .h 文件中:

+ (SingletonClass *)instance;

2) 在 .m 文件中:

+ (SingletonClass *)instance {

    static SingletonClass* instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
        //your init code here
    });
    return instance;
}

如果你想调用你的单例,只需调用[SingletonClass instance].

如果您对什么是“dispatch_once_t”感兴趣,请阅读 Grand Central Dispatch:http: //developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html

于 2012-10-09T15:47:30.673 回答
2

重新更新:

您的NSArray取消分配是因为您使用的是 autorelease 初始化程序arrayWithObjects并将其直接分配给 ivar animalNames_。因此不保留。

要解决此问题,请将数组分配给属性:

self.animalNames = [NSArray arrayWithObjects:@"giraffe", @"giraffe", @"giraffe", @"giraffe", nil];

顺便说一句,在 ARC 下,这不会成为问题,因为 ivar 将是一个强大的(保留)参考。我不会厌倦鼓励任何人切换到 ARC。它已经存在一年多了,再使用 MRC 代码绝对没有意义!看到开发人员仍然不使用更简单、更快、更直接的选项,我真的很痛苦。(咆哮) :)

于 2012-10-09T19:12:34.490 回答
-2

您可以在任何需要的地方设置一个指针。

-(void)someMethod {

MySingleton *singleton = [MySingleton sharedSingleton];
singleton.data = YES; //dumb example to show you did something...

}

-(void)someOtherMethod {

MySingleton *singleton = [MySingleton sharedSingleton]; //You have to create a new pointer...
singleton.data = NO; //another dumber example to show you did something...

}

注意:这假设您以与我相同的方式创建了一个单例...您的代码可能不同,因此导致我的答案不适用...

于 2012-10-09T15:39:06.920 回答
-3

您需要在单例类中覆盖以下方法,因为在您的程序中,如果有人已经初始化,[[SingletonClass alloc] init]那么单例将有另一个实例并释放它会导致错误。

+ (id)allocWithZone:(NSZone *)zone{
    return [[self SingletonClass] retain];  
}

- (id)copyWithZone:(NSZone *)zone{
    return self;
}

- (id)retain{
    return self;
}
于 2012-10-09T16:03:03.527 回答