Question

I'm new to objective-c and cocoa, and trying to create a document based application that saves and loads a custom class to and from the filesystem. My custom class that conforms to nscoding protocol is as follow:

NSString *const description = @"description";

@implementation PhotoItem
@synthesize  description = _description;

-(id)init {
    if(self = [super init]){
        self.description = @"";
    }
    return self;
}

/* serializing into file */
- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.description forKey:description];
}

/* deserializing */
- (id)initWithCoder:(NSCoder *)aDecoder {
    self.description = [aDecoder decodeObjectForKey:description];
    return self;
}

and my document:

@implementation AMRDocument
@synthesize  imgMainImage = _imgMainImage, lblCreationDate = _lblCreationDate, photo=_photo,
txtDescription = _txtDescription;
- (id)init
{
    self = [super init];
    if (self) {
        self.photo = [[PhotoItem alloc] init];
    }
    return self;
}

- (NSString *)windowNibName
{
    return @"AMRDocument";

}

- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
    NSLog(@"windowControllerDidLoadNib");
    [super windowControllerDidLoadNib:aController];
//    self.imgMainImage.image = self.photo.image;
    [self.txtDescription setString: self.photo.description];
}


+ (BOOL)autosavesInPlace
{
    return YES;
}

#pragma mark -saving and loading
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
//    self.photo.image = self.imgMainImage.image;
//    return [NSKeyedArchiver archivedDataWithRootObject:self.photo];

    self.photo.description = self.txtDescription.string;
    NSData *archivedData  = [NSKeyedArchiver archivedDataWithRootObject:self.photo];
    return archivedData;
}

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
{
    self.photo = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    return YES;
}



- (void)windowWillClose:(NSNotification *)notification {

}




- (IBAction)archiveClicked:(id)sender {
    self.photo = [NSKeyedUnarchiver unarchiveObjectWithFile:[@"~/desktop/myphoto1.photo"
            stringByExpandingTildeInPath]];

    [self.txtDescription setString:self.photo.description];
}

- (IBAction)archiveClicked:(id)sender {
    self.photo.description = self.txtDescription.string;
    [NSKeyedArchiver archiveRootObject:self.photo toFile:[@"~/desktop/myphoto1.photo"
            stringByExpandingTildeInPath]];
}
@end

As you can see I've created two actions called archiveClicked, and unarchiveClicked, one for writing and the other for reading from the file. It works perfectly fine.

When I'm saving the document using command+s, it can also successfully writes to the file, or at least no exception is thrown then. But when I'm trying to open up the saved file, it'll give me following exception in a popup instead of running the application and loads from the disk.

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000


Application Specific Information:
*** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (PhotoItem)'
terminate called throwing an exception
abort() called

Application Specific Backtrace 1:
0   CoreFoundation                      0x00007fff8f715b06 __exceptionPreprocess + 198
1   libobjc.A.dylib                     0x00007fff912f03f0 objc_exception_throw + 43
2   CoreFoundation                      0x00007fff8f7158dc +[NSException raise:format:] + 204
3   Foundation                          0x00007fff98a1e8c3 _decodeObjectBinary + 2559
4   Foundation                          0x00007fff98a1dd24 _decodeObject + 226
5   Foundation                          0x00007fff98a90df3 +[NSKeyedUnarchiver unarchiveObjectWithData:] + 92
6   DocumentBasedApp                    0x0000000108e49a11 -[AMRDocument readFromData:ofType:error:] + 113
7   AppKit                              0x00007fff8d764527 -[NSDocument readFromURL:ofType:error:] + 546
8   AppKit                              0x00007fff8d365348 -[NSDocument _initWithContentsOfURL:ofType:error:] + 135
9   AppKit                              0x00007fff8d364ff4 -[NSDocument initWithContentsOfURL:ofType:error:] + 262
10  AppKit                              0x00007fff8d78d765 -[NSDocumentController makeDocumentWithContentsOfURL:ofType:error:] + 332
11  AppKit                              0x00007fff8d78ce7f __block_global_12 + 230
12  AppKit                              0x00007fff8d78ca1b __block_global_8 + 955
13  AppKit                              0x00007fff8d78bdba -[NSDocumentController _openDocumentWithContentsOfURL:usingProcedure:] + 593
14  AppKit                              0x00007fff8d78c655 __block_global_7 + 273
15  libdispatch.dylib                   0x00007fff926b4f01 _dispatch_call_block_and_release + 15
16  libdispatch.dylib                   0x00007fff926b10b6 _dispatch_client_callout + 8
17  libdispatch.dylib                   0x00007fff926b60c8 _dispatch_main_queue_callback_4CF + 275
18  CoreFoundation                      0x00007fff8f6b7b4c __CFRunLoopRun + 1644
19  CoreFoundation                      0x00007fff8f6b70e2 CFRunLoopRunSpecific + 290
20  HIToolbox                           0x00007fff8df91eb4 RunCurrentEventLoopInMode + 209
21  HIToolbox                           0x00007fff8df91b94 ReceiveNextEventCommon + 166
22  HIToolbox                           0x00007fff8df91ae3 BlockUntilNextEventMatchingListInMode + 62
23  AppKit                              0x00007fff8d44c533 _DPSNextEvent + 685
24  AppKit                              0x00007fff8d44bdf2 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 128
25  AppKit                              0x00007fff8d4431a3 -[NSApplication run] + 517
26  AppKit                              0x00007fff8d3e7bd6 NSApplicationMain + 869
27  DocumentBasedApp                    0x0000000108e49652 main + 34
28  libdyld.dylib                       0x00007fff8d2647e1 start + 0

I've actually created the actions to check the correctness of my nscoding functions and it seems to be working fine, but have no clue, and cannot find anything related to my issue. Appreciate any help. Needless to say this is a part of my homework.

Edit: name of this application is "PhotoManager". Earlier I had another document based app called "DocumentBasedApp", and the exception starts with :

Process:         DocumentBasedApp [4852]
Path:            /Users/USER/Library/Caches/*/DocumentBasedApp.app/Contents/MacOS/DocumentBasedApp
Identifier:      com.cjcoax.DocumentBasedApp
Version:         1.0 (1)
Code Type:       X86-64 (Native)
Parent Process:  launchd [132]
User ID:         501
Was it helpful?

Solution 3

Finally solved, I delete everything from the cache as I could not find following path:

/Users/USER/Library/Caches/*/DocumentBasedApp.app/Contents/MacOS/DocumentBasedApp

and it started working! Bizarre!

OTHER TIPS

Your initWithCoder: needs to call [super init];.

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        self.description = [aDecoder decodeObjectForKey:description];
    }

    return self;
}

The serialized version of MyCustomClass differs from the current version in your code, probably due to changes during development.

/Users/USER/Library/Caches/*/DocumentBasedApp.app/Contents/MacOS/DocumentBasedApp

Deleting the Cache directory got rid of the old serialized data.

I had another problem with NSCoder's decodeObjectForKey method while using FXForm - it crashed without any explanation.

- (id)initWithCoder:(NSCoder *)decoder
{
  if (self = [super init]) {
    self.someObject = [decoder decodeObjectForKey:@"someObject"];
  }
  return self;
}

The reason was in memory issues. Commonly, looks like when there is no explanation of a bug in logs, it means, it's a memory issue. I forgot to use correct property attribute - copy. I used assign instead. This is correct code:

@interface MyClass : : NSObject <FXForm, NSCoding>

@property (nonatomic, copy) SomeClass *someObject;

@end

Just in case somebody meets this problem too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top