I have a custom object class with the following .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
Here is how I use the folder (in some other class):
FolderObject *newFolder=[FolderObject alloc];
newFolder.folderTitle=[textView text];
newFolder.folderContents=[[NSMutableArray alloc开发者_Go百科]init];
[folders addObject:newFolder];
Here is how I save and retrieve the custom object from 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];
And finally here is where the issue is:
FolderObject *newFolder=[folders objectAtIndex:indexPath.row];
[folderTitleLabel setText:newFolder.folderTitle];
On the second line, I get an error during runtime, but only after I exit the app and come back. When I add objects to the folders array and call the above, no problems. But if I exit the app and come back, then problems:
-[__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'
Inside of initWithCoder:
for your FolderObject
you are not properly retaining the values which will result in your crash. Make sure you use the property like this.
- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self != nil)
{
//dot notation (self.) will properly retain or copy your string
//as long as it is declared as retain or copy (I recommend copy)
self.foldersContents = [coder decodeObjectForKey:@"foldersContents"];
self.folderTitle = [coder decodeObjectForKey:@"folderTitle"];
}
return self;
}
The problem seems to be in your initWithCoder:
method:
foldersContents = [coder decodeObjectForKey:@"foldersContents"];
folderTitle = [coder decodeObjectForKey:@"folderTitle"];
The values returned by decodeObjectForKey:
are not retained for you, and as you are assigning them to ivars directly instead of via the (presumably) retain
-declared properties, they are not being retained there either. So they get auto-released the next time the autorelease pool is drained. By the time you get around to trying to use it, it just so happens that the memory location formerly used for the title is now occupied by an __NSArrayM
object; were things to work out slightly differently, you'd get a more straightforward EXC_BAD_ACCESS crash.
@Joe is right about needing to retain
the objects but why are you using
self = [[FolderObject alloc] init];
instead of
self = [super init];
Your code will leak an chunk of memory each time it's called?
I don't know if it's causing your crash (I suspect not) but it's certainly interesting.
精彩评论