【问题标题】:Somehow my singleton properties are getting released不知何故,我的单身财产正在被释放
【发布时间】:2010-08-22 19:18:11
【问题描述】:

我有一个名为PoolManager 的单例对象,它在 plist 中加载和保存一些数据。在我的整个程序中,当需要了解我的池时,它会向[PoolManager sharedPoolManager] 询问它的属性。我有一个负责设置这些属性的视图,而所有其他视图都只是从中读取。一切正常,然后不知为什么,它开始崩溃。我设置了NSZombieEnabled = YES,可以看到当我访问两个NSString 属性之一时,它们似乎已被释放。调试器消息为:*** -[CFString respondsToSelector:]: message sent to deallocated instance 0x5a336d0

我尝试回到之前的快照,一切正常,但它仍然如此。我什至使用 TimeMachine 从昨天开始回到项目,它也这样做了。我很困惑。

这里是单例对象代码... surfaceshape 字符串显然是僵尸。对不起所有NSLogs


//  MyPoolSingleton.h

#import <Foundation/Foundation.h>

#define kFileName @"data.plist"

@interface PoolManager : NSObject {
    float   volume;
    float length;
    float width;
    float depth;    
    NSString *surface;
    NSString *shape;
    BOOL isMetric;
    int fcTarget;
    int cyaTarget;
    int taTarget;
    int chTarget;
    int saltTarget;
}

@property float volume;
@property float length;
@property float width;
@property float depth;
@property (nonatomic, retain) NSString *surface;
@property (nonatomic, retain) NSString *shape;
@property BOOL isMetric;
@property int fcTarget;
@property int cyaTarget;
@property int taTarget;
@property int chTarget;
@property int saltTarget;

+ (PoolManager*)sharedPoolManager;
- (void)retrieveState;
- (void)saveState;
- (NSString*)dataFilePath;

@end

//  MyPoolSingleton.m

#import "PoolManager.h"

@implementation PoolManager

@synthesize volume;
@synthesize length;
@synthesize width;
@synthesize depth;
@synthesize surface;
@synthesize shape;
@synthesize isMetric;
@synthesize fcTarget;
@synthesize cyaTarget;
@synthesize taTarget;
@synthesize chTarget;
@synthesize saltTarget;

static PoolManager* _sharedPoolManager = nil;

+ (PoolManager*)sharedPoolManager {
    @synchronized([PoolManager class])
    {
        if (!_sharedPoolManager)
            [[self alloc] init];
        return _sharedPoolManager;
    }
    return nil;
}

+ (id)alloc {
    @synchronized([PoolManager class])
    {
        NSAssert(_sharedPoolManager == nil, @"Attempted to allocate a second instance of a singleton.");
        _sharedPoolManager = [super alloc];
        return _sharedPoolManager;
    }
    return nil;
}

- (id)init {
    self = [super init];
    return self;
}

- (void)retrieveState {
    NSLog(@"--retrieveState");
    NSString *filePath = [self dataFilePath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        NSLog(@"    fileExistsAtPath: reading array from plist");
        NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
        volume = [[array objectAtIndex:0] floatValue];
            NSLog(@"      reading array: volume = %1.1f", volume);
        length = [[array objectAtIndex:1] floatValue];
            NSLog(@"      reading array: length = %1.1f", length);
        width = [[array objectAtIndex:2] floatValue];
            NSLog(@"      reading array: width = %1.1f", width);
        depth = [[array objectAtIndex:3] floatValue];
            NSLog(@"      reading array: depth = %1.1f", depth);
        self.surface = [array objectAtIndex:4];
            NSLog(@"      reading array: surface = %@", surface);
        self.shape = [array objectAtIndex:5];
            NSLog(@"      reading array: shape = %@", shape);
        isMetric = [[array objectAtIndex:6] boolValue];
            NSLog(@"      reading array: isMetric = %d", isMetric);
        fcTarget = [[array objectAtIndex:7] intValue];
            NSLog(@"      reading array: fcTarget = %d", fcTarget);
        cyaTarget = [[array objectAtIndex:8] intValue];
            NSLog(@"      reading array: cyaTarget = %d", cyaTarget);
        taTarget = [[array objectAtIndex:9] intValue];
            NSLog(@"      reading array: taTarget = %d", taTarget);
        chTarget = [[array objectAtIndex:10] intValue];
            NSLog(@"      reading array: chTarget = %d", chTarget);
        saltTarget = [[array objectAtIndex:11] intValue];
            NSLog(@"      reading array: saltTarget = %d", saltTarget);
        [array release];
    }
    else {
        NSLog(@"    !fileExistsAtPath: intitializing values to nil/zero");
        volume = 0.0;
        length = 0.0;
        width = 0.0;
        depth = 0.0;
        surface = @"";
        shape = @"";
        isMetric = NO;
        fcTarget = 0.0;
        cyaTarget = 0.0;
        taTarget = 0.0;
        chTarget = 0.0;
        saltTarget = 0.0;
    }
}

- (void)saveState {
    NSLog(@"--saveState");
    NSMutableArray *array = [[NSMutableArray alloc] init];
        NSLog(@"      building array: volume = %1.1f", volume);
    [array addObject:[NSNumber numberWithFloat:volume]];
        NSLog(@"      building array: length = %1.1f", length);
    [array addObject:[NSNumber numberWithFloat:length]];
        NSLog(@"      building array: width = %1.1f", width);
    [array addObject:[NSNumber numberWithFloat:width]];
        NSLog(@"      building array: depth = %1.1f", depth);
    [array addObject:[NSNumber numberWithFloat:depth]];
        NSLog(@"      building array: surface = %@", surface);
    [array addObject:surface];
        NSLog(@"      building array: shape = %@", shape);
    [array addObject:shape];
        NSLog(@"      building array: isMetric = %d", isMetric);
    [array addObject:[NSNumber numberWithBool:isMetric]];
        NSLog(@"      building array: fcTarget = %d", fcTarget);
    [array addObject:[NSNumber numberWithInt:fcTarget]];
        NSLog(@"      building array: cyaTarget = %d", cyaTarget);
    [array addObject:[NSNumber numberWithInt:cyaTarget]];
        NSLog(@"      building array: taTarget = %d", taTarget);
    [array addObject:[NSNumber numberWithInt:taTarget]];
            NSLog(@"      building array: chTarget = %d", chTarget);
    [array addObject:[NSNumber numberWithInt:chTarget]];
        NSLog(@"      building array: saltTarget = %d", saltTarget);
    [array addObject:[NSNumber numberWithInt:saltTarget]];

    [array writeToFile:[self dataFilePath] atomically:YES];
    [array release];
}    

- (NSString*)dataFilePath {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    return [documentsDirectory stringByAppendingPathComponent:kFileName];
}

- (void)dealloc {
    [shape release], shape = nil;
    [surface release], surface = nil;
    [super dealloc];
}

@end

【问题讨论】:

  • 只是为了让你的代码更短,你可以做@synthesize var1, var2, var2;而不是每个人都有一个单独的行。
  • 谢谢,我已经开始回去清理类似的东西了。

标签: iphone objective-c xcode memory-management nszombie


【解决方案1】:

objectAtIndex: 给出一个自动释放的对象。您应该保留它,或者在设置它们时使用属性访问器self.surface = ...self.shape = ...

【讨论】:

  • 切换到self.surfaceself.shape 成功了。谢谢!我仍然不明白它是如何从昨晚开始运行良好然后决定开始崩溃的。那好吧。顺便说一句,是否有自动释放对象的列表,或返回自动释放对象以供参考的方法?
【解决方案2】:

我个人更喜欢以下单例模式:

+ (id) sharedPoolManager
{
    static id sharedPoolManager = nil;
    @synchronized (self) {
        if (sharedPoolManager == nil) {
             sharedPoolManager = [self new];
        }
    }
    return sharedPoolManager;
}

- (id) init
{
    if ((self = [super init]) != nil) {
         // Initialize ... nothing special here ...
    }
    return self;
}

(注意类方法中的self等价于[SomeClass class]

以上内容更简洁,我更喜欢将任何单例代码保留在initalloc 之外,因为如果需要,我还可以创建多个实例。例如在单元测试中。

我个人认为您不必保护程序员免于创建多个实例。合同很明确:sharedPoolManager 返回一个单例实例。如果那是您想要/需要的,请使用它。否则以通常的方式创建实例。

【讨论】:

  • 我喜欢这个看起来比我拥有的更好的方式,但是- (id)alloc 呢?我想过只创建一个实例并传递它,但这似乎需要更多的工作。实例化某些东西并为其分配属性以传递某些东西很容易,但我想出另一种方式的唯一方法是使用委托。
  • 单身人士真的不需要alloc。默认实现会很好。除非我误解了你想要做什么。
  • 哦。是的,[Foo new] 是 `[[Foo alloc] init]. Nobody seems to use it anymore except me, but it is perfectly legal. Part of NSObject` 的快捷方式。请参阅文档 :-)
猜你喜欢
  • 1970-01-01
  • 2017-03-20
  • 2010-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多