Singleton,NSMutableDictionary和plist

时间:2011-08-24 12:27:16

标签: objective-c ios4 singleton plist nsmutabledictionary

我的应用程序中有一个名为SettingsManager的单例,它应该负责读取/写入plist的设置。使用Cocoa With Love(zipped macro file)中的宏来合成Singleton。我只从(void)中将retain的返回类型更改为(oneway void)。这是因为iOS中的新编译器可以处理内存管理。我的问题是每当我调用savePrefs时,按钮调用选择器“挂起”活动状态,有时我得到EXC_BAD_ACCESS。所以我想我的内存管理失败了。令人惊讶的是,当没有可用的plist文件时(在应用程序安装之后),所有默认值都可以从我的NSMutableDictionary中正确存储和检索。以下是我的代码。非常感谢你的帮助。

马丁

CODE:

1 / Singleton标题

#import <Foundation/Foundation.h>

#define SALARY_PREF_KEY @"MonthlySalary"
#define DEFAULT_SALARY [NSNumber numberWithDouble: 0.0]
#define CURRENCY_PREF_KEY @"Currency"
#define DEFAULT_CURRENCY @"USD"
#define EXPENSES_PREF_KEY @"Expenses"
#define DEFAULT_EXPENSES [NSNumber numberWithDouble: 0.0]
#define TIME_INTERVAL_PREF_KEY @"TimeInterval"
#define DEFAULT_INTERVAL [NSNumber numberWithInteger: 2]
#define SAVINGS_PREF_KEY @"Savings"
#define DEFAULT_SAVINGS [NSNumber numberWithDouble: 0.0]

@interface SettingsManager : NSObject {
    NSString *prefsFilePath;
    NSMutableDictionary *settingsDictionary;
    NSNumber *salary;
    NSString *currency;
    NSNumber *expenses;
    NSNumber *timeInterval;
    NSNumber *savings;
}

+ (SettingsManager *)sharedSettingsManager;

@property (nonatomic, retain) NSString *prefsFilePath;
@property (nonatomic, retain) NSMutableDictionary *settingsDictionary;
@property (nonatomic, retain) NSNumber *salary;
@property (nonatomic, retain) NSString *currency;
@property (nonatomic, retain) NSNumber *expenses;
@property (nonatomic, retain) NSNumber *timeInterval;
@property (nonatomic, retain) NSNumber *savings;

    - (void) savePrefs;
@end

2 /实施:

#import "SynthesizeSingleton.h"
#import "SettingsManager.h"

@implementation SettingsManager

SYNTHESIZE_SINGLETON_FOR_CLASS(SettingsManager);

@synthesize settingsDictionary, 
            salary, 
            currency, 
            expenses, 
            timeInterval, 
            savings, 
            prefsFilePath;

- (id)init {
    self = [super init];  
    if (self) {
        if (prefsFilePath == nil) {
            NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0];
            prefsFilePath = [documentsDirectory stringByAppendingPathComponent:@"iEarn.plist"];
        }
        if ([[NSFileManager defaultManager] fileExistsAtPath: prefsFilePath]) {
            settingsDictionary = [[NSMutableDictionary alloc] 
                                  initWithContentsOfFile: prefsFilePath];
        } 
        else {
            settingsDictionary = [[NSMutableDictionary alloc] initWithCapacity: 7];
            [settingsDictionary setObject: DEFAULT_SALARY forKey: SALARY_PREF_KEY];
            [settingsDictionary setObject: DEFAULT_CURRENCY forKey: CURRENCY_PREF_KEY];
            [settingsDictionary setObject: DEFAULT_EXPENSES forKey: EXPENSES_PREF_KEY];
            [settingsDictionary setObject: DEFAULT_INTERVAL forKey: TIME_INTERVAL_PREF_KEY];
            [settingsDictionary setObject: DEFAULT_SAVINGS forKey: SAVINGS_PREF_KEY];
            [settingsDictionary writeToFile: prefsFilePath atomically: YES];
        }
        self.salary = [settingsDictionary objectForKey:SALARY_PREF_KEY];
        self.currency = [settingsDictionary objectForKey:CURRENCY_PREF_KEY];
        self.expenses = [settingsDictionary objectForKey:EXPENSES_PREF_KEY];
        self.timeInterval = [settingsDictionary objectForKey:TIME_INTERVAL_PREF_KEY];
        self.savings = [settingsDictionary objectForKey:SAVINGS_PREF_KEY];
    }
    return self;
}

- (void) savePrefs {
    [settingsDictionary setObject: salary forKey: SALARY_PREF_KEY];
    [settingsDictionary setObject: currency forKey: CURRENCY_PREF_KEY];
    [settingsDictionary setObject: expenses forKey: EXPENSES_PREF_KEY];
    [settingsDictionary setObject: timeInterval forKey: TIME_INTERVAL_PREF_KEY];
    [settingsDictionary setObject: savings forKey: SAVINGS_PREF_KEY];
    [settingsDictionary writeToFile: prefsFilePath atomically: YES];   
}

- (void) dealloc {
    [settingsDictionary dealloc];
    [super dealloc];
}
@end

3 /我如何致电savePrefs

- (IBAction)saveButtonPressed:(id)sender {
    [[SettingsManager sharedSettingsManager] setSalary: [NSNumber numberWithDouble: [salary.text doubleValue]]];
    [[SettingsManager sharedSettingsManager] setCurrency: currency.text];
    [[SettingsManager sharedSettingsManager] setExpenses: [NSNumber numberWithDouble: [expenses.text doubleValue]]];
    [[SettingsManager sharedSettingsManager] setTimeInterval: [NSNumber numberWithInt: [intervalStepper value]]];
    [[SettingsManager sharedSettingsManager] setSavings: [NSNumber numberWithDouble: [savings.text doubleValue]]];
    [[SettingsManager sharedSettingsManager] savePrefs];
}

1 个答案:

答案 0 :(得分:1)

您似乎直接访问prefsFilePath实例变量而不是使用其访问者:

prefsFilePath = [documentsDirectory stringByAppendingPathComponent:@"iEarn.plist"];

存储的值是自动释放的,因此在当前池耗尽后,引用不再有效。相反,你应该使用:

self.prefsFilePath = [documentsDirectory stringByAppendingPathComponent:@"iEarn.plist"];

prefsFilePath = [[documentsDirectory stringByAppendingPathComponent:@"iEarn.plist"] retain];

注意:您可以为所有属性访问添加前缀以避免出现问题,或rename the instance variables