How to archive structs like NSRect

  • I have an object which contains an NSRect which I need to archive.  What is the best way to archive this using an NSKeyedArchiver?  Do I really have to go through and archive every primitive contained in it (and sub-structures)?

    I'm looking at the Archives and Serializations Programming Guide for Cocoa (Developer Documentation) and it suggests I do this, rather than attempt to wrap it in an NSData object.  Or should I just write my own wrapper?  It's so much easier in Java where everything is an object or is easily wrapped in an object!

    Any advice, suggestions, or just pointers to where to go looking for an answer, gratefully received.

    best regards,

    Andrew
  • On Nov 12, 2007, at 3:12 PM, Andrew Ebling wrote:

    > I have an object which contains an NSRect which I need to archive.
    > What is the best way to archive this using an NSKeyedArchiver?  Do
    > I really have to go through and archive every primitive contained
    > in it (and sub-structures)?
    >
    > I'm looking at the Archives and Serializations Programming Guide
    > for Cocoa (Developer Documentation) and it suggests I do this,
    > rather than attempt to wrap it in an NSData object.  Or should I
    > just write my own wrapper?  It's so much easier in Java where
    > everything is an object or is easily wrapped in an object!
    >
    > Any advice, suggestions, or just pointers to where to go looking
    > for an answer, gratefully received

    I have 2 words for you:

    NSStringFromRect

    NSRectFromString
  • You can wrap an NSRect in an NSValue, but I just use NSRectToString
    and NSStringToRect to make it an object.

    Hope that helps,
    Hank

    On Nov 12, 2007, at 9:12 AM, Andrew Ebling wrote:

    > I have an object which contains an NSRect which I need to archive.
    > What is the best way to archive this using an NSKeyedArchiver?  Do I
    > really have to go through and archive every primitive contained in
    > it (and sub-structures)?
    >
    > I'm looking at the Archives and Serializations Programming Guide for
    > Cocoa (Developer Documentation) and it suggests I do this, rather
    > than attempt to wrap it in an NSData object.  Or should I just write
    > my own wrapper?  It's so much easier in Java where everything is an
    > object or is easily wrapped in an object!
    >
    > Any advice, suggestions, or just pointers to where to go looking for
    > an answer, gratefully received.
    >
    > best regards,
    >
    > Andrew
    >

    Hank Heijink
    <hank.list...>
  • On Nov 12, 2007, at 9:27 AM, Hank Heijink wrote:

    > You can wrap an NSRect in an NSValue, but I just use NSRectToString
    > and NSStringToRect to make it an object.
    >
    > Hope that helps,
    > Hank

    Sorry, I always forget and I didn't bother looking it up. What
    St├ęphane said. From, not To.

    H
  • On Nov 12, 2007, at 3:12 PM, Andrew Ebling wrote:

    > I have an object which contains an NSRect which I need to archive.
    > What is the best way to archive this using an NSKeyedArchiver?  Do I
    > really have to go through and archive every primitive contained in
    > it (and sub-structures)?
    >
    > I'm looking at the Archives and Serializations Programming Guide for
    > Cocoa (Developer Documentation) and it suggests I do this, rather
    > than attempt to wrap it in an NSData object.  Or should I just write
    > my own wrapper?  It's so much easier in Java where everything is an
    > object or is easily wrapped in an object!
    >
    > Any advice, suggestions, or just pointers to where to go looking for
    > an answer, gratefully received.
    >
    > best regards,
    >
    > Andrew

    How about NSGeometryKeyedCoding (see NSKeyedArchiver.h)  :

    @interface NSCoder (NSGeometryKeyedCoding)

    - (void)encodePoint:(NSPoint)point forKey:(NSString *)key;
    - (void)encodeSize:(NSSize)size forKey:(NSString *)key;
    - (void)encodeRect:(NSRect)rect forKey:(NSString *)key;

    - (NSPoint)decodePointForKey:(NSString *)key;
    - (NSSize)decodeSizeForKey:(NSString *)key;
    - (NSRect)decodeRectForKey:(NSString *)key;

    @end

    Guy Meyer
  • That doesn't work.  NSKeyedArchiver chokes on it.  That's currently high
    on my gripe list.  I resorted to class-testing and wrapping NSValues in
    NSData, although I may change to the string approach for rects.  I am
    thankful that you can now at least archive NSColor with a keyed archiver.  I
    wish they would include NSValues.  IMHO, if you can put it into an array or
    a dictionary, you should be able to archive it.

        BTW, if you take my approach of class-testing be sure and use
    "isKindOf", not "isMemberOf", because NSValue is not just a class -- it is a
    class cluster. (Found this out the hard way).

    > Message: 3
    > Date: Mon, 12 Nov 2007 09:27:33 -0500
    > From: Hank Heijink <hank.list...>
    > Subject: Re: How to archive structs like NSRect
    > To: Andrew Ebling <aebling...>
    > Cc: "<cocoa-dev...>" <cocoa-dev...>
    > Message-ID: <7E41D32C-F354-4629-90F3-AE7149BE838E...>
    > Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes
    >
    > You can wrap an NSRect in an NSValue, but I just use NSRectToString
    > and NSStringToRect to make it an object.
    >
    > Hope that helps,
    > Hank
    >
    > On Nov 12, 2007, at 9:12 AM, Andrew Ebling wrote:
  • I would like to take this opportunity to (respectfully) express my
    concerns about the apparent rift in the NSCoder classes.

    It would seem that NSArchiver is being deprecated since newer classes
    such as NSIndexPath do not implement non-keyed coding and (as Doug
    Knowles pointed out) NSPredicate no longer supports non-keyed coding
    in 10.5.  I think NSKeyedArchiver was a significant step forward in
    dealing with legacy coding issues, but there are two significant
    problems :

      1) NSPortCoder does not support keyed coding

      2) NSKeyedArchiver does not provide the same level of support for
    non-object types as NSArchiver does

    I suspect the problem which Gordon has observed with NSValue is a
    consequence of 2, since presumably NSValue's -encodeWithCoder: uses -
    encodeValueOfObjCType:at:.

    As another example of why 2 is a problem, suppose I have a triangle
    mesh object with vertices represented as a c-array of struct {float x,
    y, z;}.  With an NSArchiver I could encode the vertex array using
    either -encodeArrayOfObjCType:count:at: or -
    encodeValueOfObjCType:at:.  An NSKeyedArchiver throws an exception
    when using the non-keyed methods in this situation (although it does
    work for simpler c-types such as an array of floats).

    I realize that I could encode the vertices as NSData, but in order to
    be architecture independent I would have to first use NSArchiver to
    create the NSData and then encode the data using -encodeObject:forKey:
    -- an arguably unnecessary copy.  It would be far preferable to have a
    keyed-coding method -encodeValueOfObjCType:forKey:at: which provides
    the functionality which I have come to expect from NSArchiver.

    I have filed an enhancement request (5163604) to this effect...

    Cheers,
    dave

    On 12-Nov-07, at 11:16 AM, Gordon Apple wrote:

    > That doesn't work.  NSKeyedArchiver chokes on it.  That's
    > currently high
    > on my gripe list.  I resorted to class-testing and wrapping NSValues
    > in
    > NSData, although I may change to the string approach for rects.  I am
    > thankful that you can now at least archive NSColor with a keyed
    > archiver.  I
    > wish they would include NSValues.  IMHO, if you can put it into an
    > array or
    > a dictionary, you should be able to archive it.
    >
    > BTW, if you take my approach of class-testing be sure and use
    > "isKindOf", not "isMemberOf", because NSValue is not just a class --
    > it is a
    > class cluster. (Found this out the hard way).
    >
    >> Message: 3
    >> Date: Mon, 12 Nov 2007 09:27:33 -0500
    >> From: Hank Heijink <hank.list...>
    >> Subject: Re: How to archive structs like NSRect
    >> To: Andrew Ebling <aebling...>
    >> Cc: "<cocoa-dev...>" <cocoa-dev...>
    >> Message-ID: <7E41D32C-F354-4629-90F3-AE7149BE838E...>
    >> Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes
    >>
    >> You can wrap an NSRect in an NSValue, but I just use NSRectToString
    >> and NSStringToRect to make it an object.
    >>
    >> Hope that helps,
    >> Hank
    >>
    >> On Nov 12, 2007, at 9:12 AM, Andrew Ebling wrote:
    >
  • It's good to know this exists.  I had never seen this.  However, it
    still doesn't help in encoding an NSDictionary.  You have to put these
    things into an NSValue just to get them into the dictionary.  Then if you
    want to encode the dictionary, you have to iterate through the dictionary
    and test every entry for every particular type of NSValue to encode it.
    Then, I'm still not sure how to decode it unless you encode Type info with
    it.

        In my case, I have more than one NSDictionary, each of which hasn't an a
    priori clue as to what it contains.  The keys and objects/values are filled
    in from elsewhere.  Everything contained conforms to NSCoding.  What I would
    like is to be able to just tell it to archive/unarchive the dictionary and
    be done with it.

    > How about NSGeometryKeyedCoding (see NSKeyedArchiver.h)  :
    >
    >
    > @interface NSCoder (NSGeometryKeyedCoding)
    >
    > - (void)encodePoint:(NSPoint)point forKey:(NSString *)key;
    > - (void)encodeSize:(NSSize)size forKey:(NSString *)key;
    > - (void)encodeRect:(NSRect)rect forKey:(NSString *)key;
    >
    > - (NSPoint)decodePointForKey:(NSString *)key;
    > - (NSSize)decodeSizeForKey:(NSString *)key;
    > - (NSRect)decodeRectForKey:(NSString *)key;
    >
    > @end
    >
    >
    > Guy Meyer
    >
  • I'm coming in on the middle of this thread, so excuse me if I'm
    repeating something already covered.

    It seems like the issue isn't in encoding/decoding a NSDictionary,
    but rather correctly handling the case where objects in the
    dictionary contain a non-native representation of a struct, such as a
    NSString created by calling NSStringFromRect(). I assume from your
    comments below, that if you see a NSString that it's always just
    plain text, a NSNumber is just a number, etc. If you do need to
    support NSRects and such, then perhaps adding some type info would
    not be such a bad idea as your code would then know exactly what to
    do with each type/value pair.

    steve

    On Nov 12, 2007, at 2:50 PM, Gordon Apple wrote:

    > It's good to know this exists.  I had never seen this.
    > However, it
    > still doesn't help in encoding an NSDictionary.  You have to put these
    > things into an NSValue just to get them into the dictionary.  Then
    > if you
    > want to encode the dictionary, you have to iterate through the
    > dictionary
    > and test every entry for every particular type of NSValue to encode
    > it.
    > Then, I'm still not sure how to decode it unless you encode Type
    > info with
    > it.
    >
    > In my case, I have more than one NSDictionary, each of which
    > hasn't an a
    > priori clue as to what it contains.  The keys and objects/values
    > are filled
    > in from elsewhere.  Everything contained conforms to NSCoding.
    > What I would
    > like is to be able to just tell it to archive/unarchive the
    > dictionary and
    > be done with it.
    >
    >
    >> How about NSGeometryKeyedCoding (see NSKeyedArchiver.h)  :
    >>
    >>
    >> @interface NSCoder (NSGeometryKeyedCoding)
    >>
    >> - (void)encodePoint:(NSPoint)point forKey:(NSString *)key;
    >> - (void)encodeSize:(NSSize)size forKey:(NSString *)key;
    >> - (void)encodeRect:(NSRect)rect forKey:(NSString *)key;
    >>
    >> - (NSPoint)decodePointForKey:(NSString *)key;
    >> - (NSSize)decodeSizeForKey:(NSString *)key;
    >> - (NSRect)decodeRectForKey:(NSString *)key;
    >>
    >> @end
  • I had sent this privately earlier, but it may be of interest generally.

    You can get around the problems with keyed archiving of NSValues by
    using a coding proxy along the lines of...

    @implementation MyValueKeyedCodingProxy : NSObject
      { NSData *data; }

    - (id) initWithValue:(NSValue *)aValue
      { data = [NSArchiver archivedDataWithRootObject:aValue]; return
    self; }

    - (id) initWithCoder:(NSCoder *)coder
      { data = [coder decodeObject]; return self; }

    - (void) encodeWithCoder:(NSCoder *)coder
      { [coder encodeObject:data]; }

    - (id) awakeAfterUsingCoder:(NSCoder *)coder
      { return [NSUnarchiver unarchiveObjectWithData:data]; }

    @end

    @implementation NSValue(MyKeyedArchivingWorkaround)

    - (id) replacementObjectForKeyedArchiver:(NSKeyedArchiver *)archiver
      { return [[MyValueKeyedCodingProxy alloc] initWithValue:self]; }

    @end

    This is written hastily and expects GC, but you get the idea...

    dave

    On 12-Nov-07, at 3:50 PM, Gordon Apple wrote:

    > It's good to know this exists.  I had never seen this.  However, it
    > still doesn't help in encoding an NSDictionary.  You have to put these
    > things into an NSValue just to get them into the dictionary.  Then
    > if you
    > want to encode the dictionary, you have to iterate through the
    > dictionary
    > and test every entry for every particular type of NSValue to encode
    > it.
    > Then, I'm still not sure how to decode it unless you encode Type
    > info with
    > it.
    >
    > In my case, I have more than one NSDictionary, each of which
    > hasn't an a
    > priori clue as to what it contains.  The keys and objects/values are
    > filled
    > in from elsewhere.  Everything contained conforms to NSCoding.  What
    > I would
    > like is to be able to just tell it to archive/unarchive the
    > dictionary and
    > be done with it.
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today