Синглтон, NSMutableDictionary и plist - PullRequest
       359

Синглтон, NSMutableDictionary и plist

1 голос
/ 24 августа 2011

В моем приложении есть синглтон SettingsManager, который должен позаботиться о чтении / записи настроек в plist. Синглтон синтезируется с использованием макроса из Cocoa With Love ( zip-файл макроса ). Я только изменил тип возврата для сохранения (односторонний доступ) с (недействительный). Это связано с новым компилятором в iOS, который может позаботиться об управлении памятью. Моя проблема в том, что всякий раз, когда я вызываю savePrefs, кнопка вызова селектора «зависает» в активном состоянии, а иногда я получаю EXC_BAD_ACCESS. Так что я думаю, что мне не удалось с управлением памятью. Удивительно, но когда файл plist недоступен (сразу после установки приложения), все значения по умолчанию правильно сохраняются и извлекаются из моего NSMutableDictionary. Ниже мой код. Буду супер признателен за вашу помощь.

Martin

КОД:

1 / Singleton header

#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 Ответ

1 голос
/ 24 августа 2011

Кажется, что вы обращаетесь непосредственно к переменной экземпляра prefsFilePath вместо использования ее метода доступа:

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

Сохраненное значение автоматически высвобождается, поэтому после слива текущего пула ссылка недольше действителен.Вместо этого вы должны использовать:

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

или

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

Примечание : вы можете либо префиксировать все обращения к свойству, чтобы избежать проблем, либо переименоватьпеременные экземпляра .

...