Data Structure to Data

  • Hello,I've read that it is not recommended to create an NSData object from a
    data structure, especially... "if  the structure contains object or pointer
    fields, the data object isn't going to archive them correctly"

    What about a CFData object?

    I have a data structure that contains a pointer field.  That which it points
    to can vary is size depending on the implementation.  Right now I'm doing
    this where "data" is my structure that contains custom image data.

    unsigned int sizeOfImage = data->xsize * data->ysize * data->channels *
    sizeof(unsigned int);

    SInt32 sz = (SInt32)(sizeOfImage + sizeof(myImageStruct));

    CFDataRef imgData = CFDataCreate(kCFAllocatorDefault, data, sz);

    The CFData object is then sent as part of a CFNotification.  On the
    receiving side of the notification I do this:

    myNewImageStruct = (myImageStruct *)CFDataGetBytePtr(imgData);

    NSLog(@"%d, %d, %d, %d"
    , myNewImageStruct->xsize, myNewImageStruct->ysize,
    myNewImageStruct->channels, myNewImageStruct->bitsPerPixel);

    The NSLog call works fine but the image data in the pointer field does not
    come through (Null data)  I'm guessing that it is due what was mentioned
    above.  Is this correct?
    What would be a better way to wrap "myImageStruct" into a CFData object that
    I can send as part of a notification.

    thanks
    ----
    Bruce Johnson
    <bdjohnson01...>
  • You need to post your actual struct for this to make sense.  I can
    only assume it's something like:

    struct foo
    {
      unsigned int xsize, ysize, channels;
      unsigned int pixels[];
    }

    --Kyle Sluder
  • typedef struct{
        unsigned int xsize, ysize, channels;
        char fname[255];
        unsigned int *pixels;
    } foo;

    then in code I do something like:

    foo  *myStructFoo = (foo *) malloc (sizeof(foo));

    then later I fill in the unsigned int and char variables
    myStructFoo->xsize = 512;
    myStructFoo->ysize = 512;
    myStructFoo->channels; = 3;
    strcpy(myStructFoo->fname, "out.tif");
    ...etc;

    myStructFoo->pixels = (unsigned int *) malloc (myStructFoo->xsize
    * myStructFoo->ysize* myStructFoo->channels*sizeof(unsigned int));

    the struct also contains a large list of metadata information set as
    unsigned ints as well.  All these I can access going to and from a CFData
    object.  It is the pixel data that goes null.  I am assuming that when I
    create CFData object, it isn't dereferencing the pixel data pointer.

    thanks

    On Jan 17, 2008 10:43 PM, Kyle Sluder <kyle.sluder+<cocoa-dev...>
    wrote:

    > You need to post your actual struct for this to make sense.  I can
    > only assume it's something like:
    >
    > struct foo
    > {
    > unsigned int xsize, ysize, channels;
    > unsigned int pixels[];
    > }
    >
    > --Kyle Sluder
    >

    --
    ----
    Bruce Johnson
    <bdjohnson01...>
  • Why would CFData dereference the pointer?  You're telling it "copy the
    bytes at this address".  Those bytes happen to be three unsigned ints,
    a 255-byte array, and a pointer to an unsigned int.  It's doing
    exactly what you asked: copying the pointer.  If it did anything else,
    what you got out of the object would not be what you put in.

    By the way, what do you mean the pointer goes null: *pixels (aka
    pixels[0]) == NULL, or pixels == NULL?  Are you dereferencing the
    pointer on the same thread, in the same process, on the same machine?
    Why aren't you just using an object for this?

    --Kyle Sluder
  • > Why would CFData dereference the pointer?  You're telling it "copy the
    > bytes at this address".  Those bytes happen to be three unsigned ints,
    > a 255-byte array, and a pointer to an unsigned int.  It's doing
    > exactly what you asked: copying the pointer.  If it did anything else,
    > what you got out of the object would not be what you put in.

    Okay so there isn't a way to get it to copy what the pointer is pointing too
    then.

    > By the way, what do you mean the pointer goes null: *pixels (aka
    > pixels[0]) == NULL, or pixels == NULL?  Are you dereferencing the
    > pointer on the same thread, in the same process, on the same machine?

    no, no, yes, pixels[0] == NULL

    > Why aren't you just using an object for this?

    The source of the CFData object is not an objective-C application, it is a
    straight C CLI app.  The destination of the CFData object is an objective C
    application.  I was hoping to use the toll-free bridge between CFData and
    NSData.

    The CLI app runs over a long period of time, generating image data.  Through
    CFDistributedNotifications, I was hoping to send the image data as CFData
    attached to the notification.  The obj-c app would then pick the data and
    convert it to a displayable image.
    I got the notification part working with the CFData object working.  The
    only part is the image data itself wasn't coming through.
    --
    ----
    Bruce Johnson
    <bdjohnson01...>
  • On Jan 18, 2008 7:10 PM, Bruce Johnson <bdjohnson01...> wrote:

    > Okay so there isn't a way to get it to copy what the pointer is pointing too
    > then.

    There is no automatic deep copy, no. (If you were trying to write an
    automatic deep copy function, how would you make it determine how many
    bytes to copy?!)

    > CFDataRef imgData = CFDataCreate(kCFAllocatorDefault, data, sz);

    This code asks for a CFData to be created from a block of data
    starting at "data" whose length is "sz". But this is only ever correct
    if sizeOfImage == 0.

    Imagine you were using malloc and memcpy (i.e., the allocation and the
    copy in CFDataCreate were separated). How many times would you need to
    call memcpy?

    Hamish
  • Bruce,

    Directly encoding a struct is not going to have a happy ending.  If
    it's in process, you can pass a pointer or an NSValue created with
    +valueWithPointer.

    If you need a copy or to pass it to another process, you're going to
    need to write some encode/decode function.  In addition to the
    semantic issue of a deep copy, structs have alignment and endian
    issues.

    Also, plist structures can effectively be toll free bridged.

    <http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFProper
    tyLists/CFPropertyLists.html
    >

    For passing image data between a CLI and a user app, especially on
    the same machine, you might try writing the image data to file, and
    passing the path in the notification instead.  The file system is
    very efficient with larger sized blobs (> 128K) and pretty reasonable
    down to 16-32K.

    I'd wager that +dataWithContentsOfMappedFile: is faster than passing
    a large block of image data via notifications.
    --

    -Ben
previous month january 2008 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