Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Miglu

macrumors member
Original poster
Jan 22, 2010
74
0
I save an NSMutableArray using
Code:
[manager createFileAtPath:[NSString stringWithFormat:@"%@/%@", [url path], [savePanel nameFieldStringValue]] contents:[NSData dataWithBytes:nodes length:sizeof(*nodes)] attributes:nil]
I open it using this:
Code:
	NSData* data;
		if(!(data = [manager contentsAtPath:[url path]])){
			NSLog(@"Error was code: %d - message: %s", errno, strerror(errno));
			return;
		}
		nodes = [data bytes];
		NSLog(@"%i\n", [nodes count]);
Whatever nodes' original count is, it is 16 when I open it, and its contents have been destroyed. What is the problem?
 
Why convert to/from NSData? Are you using non-plist compatible objects in the array? If so how are they converted to/from NSData?
 
The array contains NSDatas that contain C structs. What would be a better way?
[nodes addObject: [NSData dataWithBytes:node length:sizeof(*node)]];
 
The array contains NSDatas that contain C structs. What would be a better way?
[nodes addObject: [NSData dataWithBytes:node length:sizeof(*node)]];

Probably not if you want to use a NS* class to save the structs. Simply opening the file using low-level C and saving/loading the structs using the normal C techniques might work. In all honesty the NSMutableArray options is really designed for objects.

In all of this code what is nodes? A pointer to NSMutableArray? If so simply using that as a pointer to memory that you can save/load as a bunch of bytes is not likely to work. The basic reason for this is that internally NSArray/NSMutableArray contains further pointers. Some of these are NSObject related (isa, super etc). These might work on reload. They might not. I can't comment if those sort of things always load to the same memory location. But there will be at least one more pointer: the pointer to the underlying C array. The has to be a pointer, not a fixed size array as the size of the array varies per instance. So when you save the bytes of the NSMutableArrayObject you save something like this (all addresses made up)

Code:
void *isa -> 0x1234567
void *super -> 0x0001234
void *array -> 0x66667777

That is all you are saving: you are not saving the memory area pointed to by array. When you reload the bytes you get exactly that back. isa and super might still be valid. array is now pointing at a block of memory that could realistically contain anything. I suspect the actual implementation has more pointers/layers than this but the basic problem is the same.

Finally onto a solution. The NSCoding protocol is designed to solve this problem: it lets you turn objects into bytes to save/load. NSArray supports NSCoding so you can use it. If I were you I'd read the Archives and Serializations Programming Guide.
 
I should use NSArray's encodeWithCoder. However, the section about Structures and Bit Fields explains that I should customize an archiver in order to archive the fields independently. This is an example in http://developer.apple.com/library/...ng.html#//apple_ref/doc/uid/20000949-BABGBHCA about creating an archiver:
Code:
NSMutableData *data;

data = [NSMutableData data];
archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
// Customize archiver here
[archiver encodeObject:myMapView forKey:@"MVMapView"];
[archiver finishEncoding];
Could you explain how to archive the structs' fields?
 
All I can tell you is what the documentation says:

The best technique for archiving a structure or a collection of bit fields is to archive the fields independently and chose the appropriate type of encoding/decoding method for each. The key names can be composed from the structure field names if you wish, like “theStruct.order”, “theStruct.flags”, and so on.
 
Could you give an example of archiving a struct's field.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.