NSKeyedArchiver and NSKeyedUnarchiver with NSMutableArray

I hope this is not due to the fact that I am using the Mutable array here, but it puzzles me, so it would not surprise me if that were the case.

BACKGROUND:

I created a small database, which is essentially an NSMutableArray containing custom objects that we can call recordObjects. I created an array:

database = [[NSMutableArray alloc] init]; 

and my custom object called "recordObject" contains the following variables and inits:

 NSString *name; int anInt; Bool aBool; 

I also synthesized methods so that I can make calls such as:

 aString = [[database objectAtIndex:someIndex] name]; 

And methods were added for my controller class to add, delete, and select individual records to display. So far, everything is working correctly and exactly as expected.

Then I set my class recordObject (a subclass of NSObject) to use NSCoder (by including the @interface directive and adding the following encoding and decoder methods to the implementation file:

 -(void) encodeWithCoder: (NSCoder *) encoder { [encoder encodeObject: name forKey: @"recordName"]; [encoder encodeInt: anInt forKey: @"recordInteger"]; [encoder encodeBool: aBool forKey: @"recordBool"]; } -(id) initWithCoder: (NSCoder *) decoder { name = [decoder decodeObjectForKey: @"recordName"]; anInt = [decoder decodeIntForKey: @"recordInteger"]; aBool = [decoder decodeBoolForKey: @"recordBool"]; } 

To write the file, I used the following:

 [NSKeyedArchiver archiveRootObject:database toFile:myPath]; 

When I run the program, all APPEARS is working correctly. The encoder method is called for each of the entries in the array, and the file is written to disk. Opening a file with TextEdit shows that there is data (although I mostly donโ€™t understand).

PROBLEM:

Here, where I run into an obstacle.

I added the following code to upload the file to my database array:

 database = [NSKeyedUnarchiver unarchiveObjectWithFile:myPath]; 

When I run the program again, this time loading the database, APPEARS is working correctly. My first test was to use the NSMutableArray counting method:

 x = [database count]; 

As a result, X filled in the required number of entries in the file. If 5 records were saved when I saved the database, X will be set to 5 after loading the database the next time the program runs.

Now here is the big problem:

The program crashes if I try to use ANY of my access methods. For example, if I try to use the following after loading the database:

 aString = [[database objectAtIndex:someIndex] name]; 

the program crashes and returns the following error in the console:

 Program received signal: "EXC_BAD_ACCESS". sharedlibrary apply-load-rules all 

My interpretation is that for some reason the data is not loaded or initialized in the database array, but for life I canโ€™t understand where I made a mistake here.

As an additional note, everything that I implemented was made from Stephen G. Kochanโ€™s book "Programming in Objective-C"

Any ideas would be greatly appreciated!

+6
source share
4 answers

There are several problems with your code.

Your initWithCoder: not fully implemented. You must call [super init] and return self . You must also copy or retain string object, otherwise it will be auto-implemented:

 - (id)initWithCoder:(NSCoder *)decoder { self = [super init]; if(self) { name = [[decoder decodeObjectForKey: @"recordName"] copy]; anInt = [decoder decodeIntForKey: @"recordInteger"]; aBool = [decoder decodeBoolForKey: @"recordBool"]; } return self; } 

Another problem is this line:

 database = [NSKeyedUnarchiver unarchiveObjectWithFile:myPath]; 

This is good, except for two things:

  • You do not keep a reference to the object, so it will be autoreleased.
  • NSKeyedArchiver returns an immutable object, in this case NSArray , not NSMutableArray .

You need to do this:

 database = [[NSKeyedUnarchiver unarchiveObjectWithFile:myPath] mutableCopy]; 

This will save the object (because it is a copy) and make the object a NSMutableArray .

+14
source

It doesn't seem like you are initializing recordObject objects to -initWithCoder:

Try something like this:

 -(id) initWithCoder: (NSCoder *) decoder { self = [super init]; if (self){ name = [decoder decodeObjectForKey: @"recordName"] copy]; anInt = [decoder decodeIntForKey: @"recordInteger"]; aBool = [decoder decodeBoolForKey: @"recordBool"]; } return self; } 

There is data when you archive it, but you do not open it correctly.

+4
source

Sounds like a memory management issue to me. EXC_BAD_ACCESS usually means that you are trying to access an object that has been freed. unarchiveObjectWithFile: returns an object with auto-implementation, so you need to save it if you want to save it, either with an explicit retain , or assigning it to a saved property.

+2
source

I had the same problem when unarchiving a custom object

 self.calTable = [[NSKeyedUnarchiver unarchiveObjectWithFile:calibrationFile] objectForKey:@"calTable"]; 

Based on Rob's answer, I changed to

 self.calTable = [[[NSKeyedUnarchiver unarchiveObjectWithFile:calibrationFile] mutableCopy] objectForKey:@"calTable"]; 

and he fixed all the errors.

0
source

Source: https://habr.com/ru/post/914589/


All Articles