# 4.3 - Load and Save As a document-based application, *Money.app* has to be able to load and save files. Otherwise, the user will lose their work when they quit the application. Depending on the structure of the files, I have several choices to override in `NSDocument`: **Table 4-1. Methods for loading and saving files**
  Load file Save file
Single file loadDataRepresentation:ofType: dataRepresentationOfType:
Bundle loadFileWrapperRepresentation:ofType: fileWrapperRepresentationOfType:
Low level readFromFile:ofType:, readFromURL:ofType: writeToFile:ofType:, writeToURL:ofType:
Read [*How do I implement saving and loading for simple files?*](https://web.archive.org/web/2004if_/http://developer.apple.com/documentation/Cocoa/Conceptual/Documents/Tasks/FAQ.html#//apple_ref/doc/uid/20000954/BAJBFGAG), [*How do I implement document packages (documents that are really folders, but appear to be opaque documents)?*](https://web.archive.org/web/2004if_/http://developer.apple.com/documentation/Cocoa/Conceptual/Documents/Tasks/FAQ.html#//apple_ref/doc/uid/20000954/BAJHBHGJ), and [*How do I implement loading and saving when the simple data or file wrapper API won't do?*](https://web.archive.org/web/2004if_/http://developer.apple.com/documentation/Cocoa/Conceptual/Documents/Tasks/FAQ.html#//apple_ref/doc/uid/20000954/BAJIGEFI). (Don't open all the links at once -- they're all on the same FAQ page.) In this case, `-loadDataRepresentation:ofType:` and `-dataRepresentationOfType:` are enough. `Document.m:` ```objc - (NSData*) dataRepresentationOfType: (NSString*) type { if (type == nil) { type = @"mon"; } if ([type isEqualToString: @"mon"]) { return [NSArchiver archivedDataWithRootObject: records]; } else { return nil; } } - (BOOL) loadDataRepresentation: (NSData*) data ofType: (NSString*) type { if ([type isEqualToString: @"mon"]) { [records setArray: [NSUnarchiver unarchiveObjectWithData: data]]; return YES; } return NO; } ``` When the user saves the document, `Document` will recieve `-dataRepresentationOfType:`. The type will be the `NSName` of the `NSType` in the property list of this application (`MoneyInfo.plist`), which is `mon`. Here, we use `NSArchiver` to transform the whole `NSArray` into `NSData`, and we don't need to worry about the format of the file. When document is going to be loaded, it will call `-loadDataRepresentation:ofType:`. We use `NSUnarchiver` to transform the `NSData` into `NSArray`. That's all. If you are using your own data structure, you have to deal with [*data archives*](https://web.archive.org/web/2004if_/http://developer.apple.com/documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/Archiving/index.html) by yourself. > Here is a related article: [*Using the Property List Objects and the NSCoding Protocol*](http://cocoadevcentral.com/articles/000059.php). ```{note} If you've ever used Python's `pickle`, `NSArchiver` is similar, but doesn't have the problem that pickles actually contain commands that are executed. `NSArchiver` simply represents the data itself as a binary file, not as a list of commands to piece together the data like `pickle` does. ``` The saved data is in binary format, which is usually undesired. Since we only use the basic data structure, we could save it into an OpenStep-style property list, which is human-readable. `Document.m:` ```objc - (NSData*) dataRepresentationOfType: (NSString*) type { if (type == nil) { type = @"mon"; } if ([type isEqualToString: @"mon"]) { return [[records description] dataUsingEncoding: [NSString defaultCStringEncoding]]; } else { return nil; } } - (BOOL) loadDataRepresentation: (NSData*) data ofType: (NSString*) type { if ([type isEqualToString: @"mon"]) { NSString *string = [[NSString alloc] initWithData: data encoding: [NSString defaultCStringEncoding]]; [records setArray: [string propertyList]]; RELEASE(string); return YES; } return NO; } ``` I use -description to get the property list, which is NSString. Then use -dataUsingEncoding to transform property list (NSString) into NSData for saving. And do the opposite for the loading. Now, you can look at the saved file, which is very easy to read. > Here is the source code for the easy-read version: [LoadSave-src.tar.gz](http://gnustep.made-it.com/GSPT/LoadSave/LoadSave-src.tar.gz). ```{note} On macOS, this will save as an XML or binary property list, since macOS no longer uses OpenStep-style property lists. ``` If you are saving the document into a directory, such as if your app saves rich text documents with images, you may want to use `-loadFileWrapperRepresentation:ofType:` and `-fileWrapperRepresentationOfType:`. The methods `-readFromFile:ofType:` and `-writeToFile:ofType:` offer the ability to access the file system directly. ------------------------------------------------------------------------