单例、NSMutableDictionary 和 plist
Posted
技术标签:
【中文标题】单例、NSMutableDictionary 和 plist【英文标题】:Singleton, NSMutableDictionary and plist 【发布时间】:2011-08-24 12:27:16 【问题描述】:我的应用中有一个名为 SettingsManager 的单例,它应该负责对 plist 的读/写设置。 Singleton 是使用来自 Cocoa With Love (zipped macro file) 的宏合成的。我只是将保留的返回类型从 (void) 更改为 (oneway void)。这是由于 ios 中的新编译器可以处理内存管理。我的问题是,每当我调用 savePrefs 时,调用选择器的按钮都会在活动状态下“挂起”,有时我会收到 EXC_BAD_ACCESS。所以我想我在内存管理方面失败了。令人惊讶的是,当没有可用的 plist 文件时(在应用程序安装后立即),所有默认值都会正确存储并从我的 NSMutableDictionary 中检索。下面是我的代码。将非常感谢您的帮助。
马丁
代码:
1/ 单例标题
#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】:您似乎直接访问了prefsFilePath
实例变量,而不是使用它的访问器:
prefsFilePath = [documentsDirectory stringByAppendingPathComponent:@"iEarn.plist"];
存储的值是自动释放的,所以在当前池耗尽后,引用不再有效。相反,您应该使用:
self.prefsFilePath = [documentsDirectory stringByAppendingPathComponent:@"iEarn.plist"];
或
prefsFilePath = [[documentsDirectory stringByAppendingPathComponent:@"iEarn.plist"] retain];
注意:您可以为所有属性访问添加前缀以避免出现问题,或者rename the instance variables。
【讨论】:
非常感谢!它挽救了这个问题。我实际上是在代码中到处寻找错误,但在 prefsFilePath 分配中......由于我来自 Java,仍然需要学习很多关于内存管理的知识。但是与强制 GC 运行相比,拥有更低级别的控制感觉是正确的。再次感谢!以上是关于单例、NSMutableDictionary 和 plist的主要内容,如果未能解决你的问题,请参考以下文章
读取和写入 NSMutableDictionary 到 plist 文件
NSDictionary 和 NSMutableDictionary 组合
iOS NSMutableDictionary中UIImage的存储和读取
从一个类访问和更改 NSMutableDictionary 的值到另一个 iOS
c# 中 NSMutableDictionary()、NSMutableArray()、NSArray 和 NSDictionary 的等价物是啥?