首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iPhone +NSCoding/NSKeyedArchiver

iPhone +NSCoding/NSKeyedArchiver
EN

Stack Overflow用户
提问于 2010-10-18 18:57:31
回答 1查看 935关注 0票数 1

我有一个小问题与NSCoding和NSKeyedArchiver当我的应用程序设置类持久化,希望有人能发现一个问题,如果这是我的代码,我相对较新的Obj-C,但有丰富的编码经验,在许多语言,所以代码似乎对我没问题,但…

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

代码语言:javascript
复制
@interface AppDelegate : NSObject <UIApplicationDelegate> {
    Settings *settings;
    [...] 
}

@property (nonatomic, retain) Settings *settings;
[...]

它在applicationDidFinishLaunching事件中创建为:

代码语言:javascript
复制
settings = [Settings LoadSettings];

如果我注释掉上面的行,那么应用程序每次都工作得很好,但是如果我使用NSCoder和NSKeyedUnarchiver从持久化设置中拉回对象,则会抛出SIGARBT错误,因为正在发送NSCFString选择器来获取编码为布尔属性的内容?设置类被定义为实现协议的NSObject。

代码语言:javascript
复制
@interface Settings : NSObject <NSCoding>

正如我所说的,创建设置类的实例很好,没有问题,保存它似乎没问题,检查从LoadSettings方法返回的类显示了正确的值,只有在退出该方法之后,预期的布尔值似乎才会作为NSCFString发送到load方法

代码语言:javascript
复制
- (id)initWithCoder:(NSCoder *)decoder {
    if (self = [super init]) {
            [...]
        self.animateMenus = [decoder decodeBoolForKey:@"animateMenus"];
    }

    return self;
}

- (void)encodeWithCoder:(NSCoder *)encoder {
    [...]
    [encoder encodeBool:animateMenus forKey:@"animateMenus"];
}

加载设置后,相关属性的使用方式如下:

代码语言:javascript
复制
SettingsViewController *settingsView = [[SettingsViewController alloc] initWithNibName:@"SettingsView" bundle:nil];
[self presentModalViewController:settingsView animated:[AppDelegate instance].settings.animateMenus];
[settingsView release];

** settings类的animateMenus成员现在将抛出以下内容:

-NSCFString animateMenus:无法识别的选择器发送到实例0xc712570 2010-10-15 11:12:51.828 App900:207 *由于未捕获的异常'NSInvalidArgumentException',正在终止应用程序,原因:'-NSCFString animateMenus:无法识别的选择器发送到实例0xc712570‘

然而,在应用程序启动时调用'settings = Settings LoadSettings;‘就可以解决这个问题(但总是使用应用程序的默认设置)?

Load和Save方法:

代码语言:javascript
复制
+ (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的所有其他成员都是instance。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-10-18 19:13:44

您需要做的是:

代码语言:javascript
复制
settings = [[Settings LoadSettings] retain];

这是因为在您的LoadSettings中,NSKeyedUnarchiver的结果是一个自动释放的对象。它被释放了:-)在那个位置创建了一个新的对象,在本例中是一个NSString。

编辑:

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

由于方法名LoadSettings在其名称中不包含alloccopynew,因此约定它应该返回一个自动释放的对象。因此,您应该这样做:

代码语言:javascript
复制
    if (data == nil) {
        s = [[Settings alloc] init];
        [s Initialise];
        [s SaveSettings];
        [s autorelease];
    }
    else
        ...
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3958439

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档