Saving in Document-Based Application

Discussion in 'Mac Programming' started by Blakeasd, Feb 16, 2011.

  1. Blakeasd macrumors 6502a

    Joined:
    Dec 29, 2009
    #1
    Hello,
    I just finished an application, so I was testing it. When I clicked on the save button to save a file, my application said the file cannot be saved. Do you have to do something so you can save stuff, as this is my first Document-Based application.
     
  2. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #2
    This page explains what you need to override in your NSDocument subclass. The entire section on document-based applications is useful information to know. Also, you might want to look at the example apps listed at the top of the NSDocument documentation.
     
  3. Blakeasd thread starter macrumors 6502a

    Joined:
    Dec 29, 2009
    #3
    I read through the documentation you provided, but I still can't figure it out. :confused:

    Here is an image of my document types settings, because I changed some stuff here without knowing what im doing, hopefully this will provide some clues about what's wrong:
    [​IMG]

    Any idea?
    Thanks :)
     
  4. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #4
    Perhaps the easiest methods for saving and loading files is in binary plist format. To do this, you implement -dataOfType:error: (saving) and -readFromData:eek:fType:error: (opening). Here you would use NSKeyed(Un)Archiver to create or decode your file, typically using the class method with "root" in the name.

    Your document should be a tree of objects that recursively encode/decode each other: to do this, you need to implement NSCoding protocol in every object that will be saved in the tree so that every -encodeWithCoder: method has a matching -initWithCoder: method and everything you need to save will be in the archive tree.

    Archiving docs
     
  5. Blakeasd thread starter macrumors 6502a

    Joined:
    Dec 29, 2009
    #5
    The program no longer gives me an error when the user clicks Save.
    This is my saving code in

    Code:
    - (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
    


    Code:
    return [NSKeyedArchiver archivedDataWithRootObject:[backgroundWell color]];
    
    The user can save, but upon opening the file it doesn't keep the color wells color value.
    Please Help
    Thanks
     
  6. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #6
    Post the code for reading the file.
     
  7. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #7
    Put in a method to read the object from the archive. You need to use the opposite method override -readFromData: ofType:error: , construct the object and return a bool to indicate success or failure. You need to use the opposite of NSKeyedArchiver (which is only for encoding).
     
  8. Blakeasd thread starter macrumors 6502a

    Joined:
    Dec 29, 2009
    #8
    I know what method to use to open (unarchive) the files, but I am confused about how to use it. I did look at the documentation, but I still don't understand. How exactly do I use the method?
     
  9. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #9
    What does the method you are looking at return? What are you trying to get from the archive? Can you get those things to match up? Sorry if I seem to be being obtuse: you will probably retain this stuff better the more you have to work out yourself.

    (Also, keep memory management in mind: you may have to retain the returned object if you are not using GC.)
     
  10. Blakeasd thread starter macrumors 6502a

    Joined:
    Dec 29, 2009
    #10
    I want to use the unarchiveObjectWithData: method. The problem is i'm not sure how to return the value of my previously archived data. How do I get the archived data from my previous method so I can return it here?
     
  11. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #11
    You do not have to worry about where you get the data. If you look at the docs that describe message flow in NSDocument, the open method goes to the file reading methods, which ultimately use something like [NSData dataWithContentsOfFile:theFile]; to get the data for your document to reconstitute itself. You have to override at least one method in the file reading and writing sequence in order to open and save. The -dataOfType:error: and -readData: ofType:error: methods are the last ones in the sequence, so if you override them, everything else is handled transparently for you. If all you need is to fetch and save a lump of data, that is all there is to it, apart from implementing NSCoding in any other custom objects you might be storing in your file.
     
  12. Blakeasd thread starter macrumors 6502a

    Joined:
    Dec 29, 2009
    #12
    How do I get the file path of the saved file as one of the parameters is the path?
     
  13. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #13
    If you are using dataOfType methods, you have no real need to interact directly with the actual file, NSDocument handles that for you. If you really do need the path, you can query the document for its file URL and convert that to a path, but if you were to do that during the saving process, you might find out that the actual file being written to is a temporary file.
     
  14. Blakeasd thread starter macrumors 6502a

    Joined:
    Dec 29, 2009
  15. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #15
    If you just use the dataOfType methods, your NSDocument subclass will decide how to encode (for saving) and decode (for opening) its data. Imagine a simple application for editing images: your document object will have an ivar that represents the image data, say a NSImage or an array containing NSImages (layers, for example) that you will connect to the view that edits them. All you would need to do is encode that ivar (for saving) and return that encoded data in the -dataOfType:error: method, which will then be written to the file for you.

    Then, when the user opens the file, you receive the data from the file as a parameter to the -readFromData: ofType:error: which you decode into that same ivar (which you have to retain).
    Code:
    - (BOOL)readFromData:(NSData *)theData ofType:(NSString *)type error:(NSError **)error {
        documentData = [NSKeyedUnarchiver unarchiveObjectWithData:theData];
        // check here for nil if you want to return a useful decoding error description
        Return ( documentData != nil );
    }
    This is all you need to do, NSDocument will handle the open and save dialogs and other things (such as "Open Recent >") for you. Get the encoding and decoding part working first, then if you really do need to work directly with the files, you can deal with that at the appropriate time.
     

Share This Page