将自定义对象保存到NSUserDefaults的问题

时间:2011-09-02 13:22:24

标签: iphone objective-c cocoa-touch

我有一个自定义对象类,其中包含以下.m:

@implementation FolderObject

    @synthesize folderTitle, folderContents; //title is NSString, contents is array

    - (id)init
    {
        self = [super init];
        if (self) {
        }
        return self;
    }

    - (void)encodeWithCoder:(NSCoder *)coder {
        [coder encodeObject:foldersContents forKey:@"foldersContents"];
        [coder encodeObject:folderTitle forKey:@"folderTitle"];

    }
    - (id)initWithCoder:(NSCoder *)coder {
        self = [[FolderObject alloc] init];
        if (self != nil)
        {
            foldersContents = [coder decodeObjectForKey:@"foldersContents"];
            folderTitle = [coder decodeObjectForKey:@"folderTitle"]; 
        }   
        return self;
    }
    @end

以下是我如何使用该文件夹(在其他一些类中):

FolderObject *newFolder=[FolderObject alloc];
        newFolder.folderTitle=[textView text];
        newFolder.folderContents=[[NSMutableArray alloc]init];

        [folders addObject:newFolder];

以下是我如何从NSUserDefaults保存和检索自定义对象:

-(void)viewDidDisappear:(BOOL)animated
{
    [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:folders] forKey:@"folders"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}
-(void)viewWillAppear:(BOOL)animated
{
    NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
    NSData *dataRepresentingSavedArrayFolders = [currentDefaults objectForKey:@"folders"];
    if (dataRepresentingSavedArrayFolders != nil)
    {
        NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArrayFolders];
        if (oldSavedArray != nil) {
            folders = [[NSMutableArray alloc] initWithArray:oldSavedArray];
        }
        else {
            folders = [[NSMutableArray alloc] init];
        }
    }

    else folders=[[NSMutableArray alloc] init];

最后问题出在这里:

        FolderObject *newFolder=[folders objectAtIndex:indexPath.row];
        [folderTitleLabel setText:newFolder.folderTitle];

在第二行,我在运行时遇到错误,但只有在我退出应用程序并返回之后。当我向文件夹数组添加对象并调用上面的内容时,没有问题。但是,如果我退出应用程序然后回来,那么问题就出现了:

 -[__NSArrayM isEqualToString:]: unrecognized selector sent to instance 0x4b9e400
2011-09-02 08:09:24.290 MyApp[43504:b303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM isEqualToString:]: unrecognized selector sent to instance 0x4b9e400'

3 个答案:

答案 0 :(得分:2)

initWithCoder:的{​​{1}}内部,您没有正确保留导致崩溃的值。确保你使用这样的属性。

FolderObject

答案 1 :(得分:0)

问题似乎出现在initWithCoder:方法中:

        foldersContents = [coder decodeObjectForKey:@"foldersContents"];
        folderTitle = [coder decodeObjectForKey:@"folderTitle"]; 

decodeObjectForKey:返回的值不会保留给您,并且当您将它们直接分配给ivars而不是通过(可能)retain声明的属性时,它们不会保留在那里。因此,下次自动释放池耗尽时,它们会自动释放。当你开始尝试使用它时,之前用于标题的内存位置现在被__NSArrayM对象占用;如果事情有所不同,你会得到一个更简单的EXC_BAD_ACCESS崩溃。

答案 2 :(得分:0)

@Joe对于需要retain对象是正确的,但你为什么要使用

self = [[FolderObject alloc] init];

而不是

self = [super init];

每次调用代码时,你的代码都会泄漏一块内存吗?

我不知道它是否会导致你的崩溃(我怀疑没有),但它确实很有趣。