iPhone+;NSCoding/NSKeyedArchiver

iPhone+;NSCoding/NSKeyedArchiver,iphone,Iphone,在坚持我的应用程序设置类时,我在NSCoding和NSKeyedArchiver方面有一个小问题,我希望有人能发现一个问题,如果这是我的代码,我对Obj-C相对较新,但在多种语言中有丰富的编码经验,所以代码对我来说似乎没问题,但是 我有一个实例类来保存我的应用程序设置,该类本身是主应用程序委托的保留属性,它是通过 @interface AppDelegate : NSObject <UIApplicationDelegate> { Settings *settings;

在坚持我的应用程序设置类时,我在NSCoding和NSKeyedArchiver方面有一个小问题,我希望有人能发现一个问题,如果这是我的代码,我对Obj-C相对较新,但在多种语言中有丰富的编码经验,所以代码对我来说似乎没问题,但是

我有一个实例类来保存我的应用程序设置,该类本身是主应用程序委托的保留属性,它是通过

@interface AppDelegate : NSObject <UIApplicationDelegate> {
    Settings *settings;
    [...] 
}

@property (nonatomic, retain) Settings *settings;
[...]
如果我注释掉上面的行,那么应用程序每次都可以正常工作,但是如果我使用NSCoder和NSKeyedUnarchiver将项目从持久化设置中拉回来,则会在为编码为布尔属性的内容发送NSCFString选择器时抛出SIGARBT错误?Settings类定义为实现协议的NSObject

@interface Settings : NSObject <NSCoding>
加载设置后,将按如下方式使用相关属性:

SettingsViewController *settingsView = [[SettingsViewController alloc] initWithNibName:@"SettingsView" bundle:nil];
[self presentModalViewController:settingsView animated:[AppDelegate instance].settings.animateMenus];
[settingsView release];
**设置类的animateMenus成员现在将抛出以下内容:

-[NSCFString animateMenus]:发送到实例0xc712570 2010-10-15 11:12:51.828应用程序[900:207]*由于未捕获异常“NSInvalidArgumentException”,终止应用程序,原因:'-[NSCFString animateMenus]:发送到实例0xc712570的未识别选择器'

鉴于,采用'settings=[settings LoadSettings];'退出应用程序启动会消除该问题(但始终使用应用程序默认值)

加载和保存方法:

+ (Settings*) LoadSettings { 
    Settings *s = nil;

    @try {
        NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"settings"];

        if (data == nil) {
            s = [[Settings alloc] init];
            [s Initialise];
            [s SaveSettings];
        }
        else
            s = (Settings*)[NSKeyedUnarchiver unarchiveObjectWithData:data];
    }
    @catch (NSException * e) {
        NSLog(@"Error Loading Settings\n%@", [e reason]);
    }
    @finally {
        return s;
    }
}

// Saves the settings dictionary to the user's device documents folder..
- (void) SaveSettings { 
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"settings"];
}
Load是一种静态方法,设置的所有其他成员都是实例。

您需要执行以下操作:

settings = [[Settings LoadSettings] retain];
这是因为在LoadSettings中,NSKeyedUnachiver的结果是一个自动释放的对象。它被释放:-)在那个位置创建了一个新对象,在本例中是一个NSString

编辑:

嗯,我刚注意到LoadSettings的一个主要问题,一开始我没有注意到:您混合了内存释放策略:在一个代码路径中,您返回未自动删除的
[[Settings alloc]init]
的结果,而在另一个代码路径中,您保留自动删除的NSKeyedArchiver的结果。您需要确保只使用一个概念

由于方法名LoadSettings的名称中不包含
alloc
copy
new
,因此惯例是它应该返回一个自动删除的对象。因此,你应该:

    if (data == nil) {
        s = [[Settings alloc] init];
        [s Initialise];
        [s SaveSettings];
        [s autorelease];
    }
    else
        ...

太好了,谢谢!我认为,通过将静态LoadSettings方法返回的指针分配到app委托中的保留指针中,它将被保留,而不管它的初始发布类型如何。现在我对iPhone上的内存管理策略有了更多的了解。
settings = [[Settings LoadSettings] retain];
    if (data == nil) {
        s = [[Settings alloc] init];
        [s Initialise];
        [s SaveSettings];
        [s autorelease];
    }
    else
        ...