Mapkit annotation arrays and writing to a file

  • I've noticed problems before with structs and NSJSONSerializaion.

    I was trying to write out a dictionary (or array) of the contents of mapView.annotations, yet writeDictToFile fails, while it writes a simple dict just fine.

    Is there a problem with the structs within the annotations, namely, the CLLocationCoordinate2D struct for each annotation, that prevents this from being able to be written out to a dictionary or array?

    Thanks in advance.
  • On May 8, 2012, at 2:08 PM, Alex Zavatone wrote:

    > I've noticed problems before with structs and NSJSONSerializaion.
    > I was trying to write out a dictionary (or array) of the contents of mapView.annotations, yet writeDictToFile fails, while it writes a simple dict just fine.
    > Is there a problem with the structs within the annotations, namely, the CLLocationCoordinate2D struct for each annotation, that prevents this from being able to be written out to a dictionary or array?

    I don’t know what you mean by ‘struct’ here — C structs aren’t Objective-C objects, so they can’t appear in a Cocoa collection.

    I do know that NSJSONSerialization only supports data types defined in JSON, i.e. NSDictionary, NSArray, NSString, NSNumber, NSNull. If your object tree has instances of any other classes in it, the encoder will throw an exception.

    —Jens
  • Well, I had a similar problem saving the information to a JSON file and had to rebuild the dictionary without the CLLocationCoordinate2D struct, before NSJSONSerialization would serialize the dictionary.

    The reason I think it's a struct is that's how it's defined in CLLocation.h and right now in the debugger, annotation is showing as (struct objc_object * const), which sorta conflicts with what you wrote (TTBOMK).

    Here are the details from CLLocation.h:

    /*
    *  CLLocationCoordinate2D
    *
    *  Discussion:
    *    A structure that contains a geographical coordinate.
    *
    *  Fields:
    *    latitude:
    *      The latitude in degrees.
    *    longitude:
    *      The longitude in degrees.
    */
    typedef struct {
    CLLocationDegrees latitude;
    CLLocationDegrees longitude;
    } CLLocationCoordinate2D;

    On May 8, 2012, at 5:27 PM, Jens Alfke wrote:

    >
    > On May 8, 2012, at 2:08 PM, Alex Zavatone wrote:
    >
    >> I've noticed problems before with structs and NSJSONSerializaion.
    >> I was trying to write out a dictionary (or array) of the contents of mapView.annotations, yet writeDictToFile fails, while it writes a simple dict just fine.
    >> Is there a problem with the structs within the annotations, namely, the CLLocationCoordinate2D struct for each annotation, that prevents this from being able to be written out to a dictionary or array?
    >
    > I don’t know what you mean by ‘struct’ here — C structs aren’t Objective-C objects, so they can’t appear in a Cocoa collection.
    >
    > I do know that NSJSONSerialization only supports data types defined in JSON, i.e. NSDictionary, NSArray, NSString, NSNumber, NSNull. If your object tree has instances of any other classes in it, the encoder will throw an exception.
    >
    > —Jens
  • On 5/8/12 2:35 PM, Alex Zavatone wrote:
    > Well, I had a similar problem saving the information to a JSON file
    > and had to rebuild the dictionary without the CLLocationCoordinate2D
    > struct, before NSJSONSerialization would serialize the dictionary.
    >
    > The reason I think it's a struct is that's how it's defined in
    > CLLocation.h and right now in the debugger, annotation is showing as
    > (struct objc_object * const), which sorta conflicts with what you
    > wrote (TTBOMK).
    >
    > Here are the details from CLLocation.h:

    No one disputes that CLLocationCoordinate2D is a struct.  What Jens is
    saying is that you can't store an unwrapped struct in a Cocoa collection
    - be it a dictionary, array, or set.

    What's getting lost in translation here is that -annotations is an array
    of objects of type id <MKAnnotation>.

    What sort of object conforming to MKAnnotation are you adding to your
    annotations array?  Whatever it is, it must have a -coordinate property.
    It is *this* property this is a CLLocationCoordinate2D struct.  This is
    how the data is getting stored in a Cocoa collection.

    In any event, I don't see how you could directly serialize your
    annotation object to a JSON object for exactly the reason Jens described
    (i.e. type incompatibility).

    If you need to convert to JSON you could, for example, write an
    NSValueTransformer that converts your id <MKAnnotation> to an
    NSDictionary that is compliant with NSJSONSerialization requirements.

    Assuming that you are planning on using JSON to communicate with a web
    service, though, you will need to determine what data structure the
    service is expecting and emit that.

    --
    Conrad Shultz

    Synthetiq Solutions
    www.synthetiqsolutions.com
  • On 5/8/12 2:35 PM, Alex Zavatone wrote:

    Or, more straightforward than my NSValueTransformer suggestion (which is
    I suppose of diminished value, no pun intended, in this scenario), you
    could just add methods to your annotation object (via category if you
    don't control the object itself), like:

    - (id)initWithJSONSerializableRepresentation:(NSDictionary *)aDictionary;
    - (NSDictionary *)JSONSerializableRepresentation;

    that would convert to/from a serializable object.

    --
    Conrad Shultz

    Synthetiq Solutions
    www.synthetiqsolutions.com
  • On May 8, 2012, at 5:53 PM, Conrad Shultz wrote:

    > On 5/8/12 2:35 PM, Alex Zavatone wrote:
    >> Well, I had a similar problem saving the information to a JSON file
    >> and had to rebuild the dictionary without the CLLocationCoordinate2D
    >> struct, before NSJSONSerialization would serialize the dictionary.
    >>
    >> The reason I think it's a struct is that's how it's defined in
    >> CLLocation.h and right now in the debugger, annotation is showing as
    >> (struct objc_object * const), which sorta conflicts with what you
    >> wrote (TTBOMK).
    >>
    >> Here are the details from CLLocation.h:
    >
    > No one disputes that CLLocationCoordinate2D is a struct.  What Jens is
    > saying is that you can't store an unwrapped struct in a Cocoa collection
    > - be it a dictionary, array, or set.
    >
    > What's getting lost in translation here is that -annotations is an array
    > of objects of type id <MKAnnotation>.
    >
    > What sort of object conforming to MKAnnotation are you adding to your
    > annotations array?  Whatever it is, it must have a -coordinate property.
    > It is *this* property this is a CLLocationCoordinate2D struct.  This is
    > how the data is getting stored in a Cocoa collection.
    >
    > In any event, I don't see how you could directly serialize your
    > annotation object to a JSON object for exactly the reason Jens described
    > (i.e. type incompatibility).
    >
    > If you need to convert to JSON you could, for example, write an
    > NSValueTransformer that converts your id <MKAnnotation> to an
    > NSDictionary that is compliant with NSJSONSerialization requirements.

    It looks like my mentioning JSON serialization added to the lack of clarity of my email, but it is another issue entirely.  I just used it as a reference problem since I ran into this issue with structs before causing JSONSerialization to barf.

    In this case, I was/am trying to write out an MapKitView's annotation array as an array or a dict with writeToFile to create a pList, and at some point, read it back in to restore the annotationList.

    I was under the tragically misinformed understanding that since a mapKitView's annotations array was already an array, that I could either write it out to a file directly (on iOS) or declare a key, add it to a dictionary and write it out without doing much of anything special.

    When I add my annotations to the mapView's annotations, I'm doing it like so:

      CLLocationCoordinate2D coordinate;
      coordinate.latitude = latitude.doubleValue;
      coordinate.longitude = longitude.doubleValue;

      MyLocation *annotation = [[MyLocation alloc] initWithName:title address:address coordinate:coordinate];
      [self.mapView addAnnotation:annotation];

    MyLocation conforms to <MKAnnotation> and is where I have coordinate defined as type CLLocationCoordinate2D.

    I'll just walk the annotations array as before, and create another array or dict that will write out a valid dict or array.

    Then I'll go over the CoreData samples which seem to address this, or as you suggested, learn the NSTransform bits.

    Thanks both of you.

    - Alex
previous month may 2012 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 31      
Go to today