parsing NSData object for information

I have a NSData object coming back from my server, it varies in its content but sticks to a particular structure.

I would like to know (hopfully with some example code) how to work though this object to get the data I need out of it.

  • Adding a subview to UIButton
  • UIPageViewController direction only forward
  • Google Cloud Messaging shows “notRegistered” when using iOS distributed app
  • How to add a UIImage with UIGesture to most views in an application.
  • hex colors in iOS are not accurate
  • How do I set default values on new properties for existing entities after light weight core data migration?
  • the structure of the data objects inside the objects are like this

    • leading value (UInt16) – (tells me what section of the response it is)
    • Size of string (UInt32) or number – (UInt32)
    • String (not null terminated) i.e. followed by the next leading value.

    I have been reading through the Binary Data Programming Guide however that’s only really showing me how to put my data into new NSData objects and accessing and compairing the bytes.

    The thing I am stuck on is how do I say grab the info dynamically. Check the NSdata objects first leading value figure out if its string or int then get the string or int and move onto the next leading value..

    any suggestions or example code would be really helpfull.. just stuck in abit of a mind block as I have never attempted anything like this in objective C.

    2 Solutions Collect From Internet About “parsing NSData object for information”

    Some of this depends on how your server is written to encode the data into what it is sending you. Assuming it is encoding the numeric values using standard network byte ordering (big-endian) you will want it converted to the correct byte-ordering for iOS (I believe that is always little-endian).

    I would approach it something like this:

    uint16_t typeWithNetworkOrdering, typeWithLocalOrdering;
    uint32_t sizeWithNetworkOrdering, sizeWithLocalOrdering;
    char *cstring = NULL;
    uint32_t numberWithNetworkOrdering, numberWithLocalOrdering;
    const void *bytes = [myData bytes];
    NSUInteger length = [myData length];
    
    while (length > 0) {
        memcpy(&typeWithNetworkOrdering, bytes, sizeof(uint16_t));
        bytes += sizeof(uint16_t);
        length -= sizeof(uint16_t);
        memcpy(&sizeWithNetworkOrdering, bytes, sizeof(uint32_t));
        bytes += sizeof(uint32_t);
        length -= sizeof(uint32_t);
        typeWithLocalOrdering = CFSwapInt16BigToHost(typeWithNetworkOrdering);
        sizeWithLocalOrdering = CFSwapInt32BigToHost(sizeWithNetworkOrdering);
    
        if (typeWithLocalOrdering == STRING_TYPE) { // STRING_TYPE is whatever type value corresponds to a string
            cstring = (char *) malloc(sizeWithLocalOrdering + 1);
            strncpy(cstring, bytes, sizeWithLocalOrdering);
            cstring[sizeWithLocalOrdering] = '\0';
            NSString *resultString = [NSString stringWithCString:cstring encoding:NSUTF8StringEncoding];
            NSLog(@"String = %@", resultString);
            free(cstring);
            bytes += sizeWithLocalOrdering;
            length -= sizeWithLocalOrdering;
            // Do whatever you need to with the string
        }
        else if (typeWithLocalOrdering == NUMBER_TYPE) { // NUMBER_TYPE is whatever type value corresponds to a number
            memcpy(&numberWithNetworkOrdering, bytes, sizeof(uint32_t));
            numberWithLocalOrdering = CFSwapInt32BigToHost(numberWithNetworkOrdering);
            NSLog(@"Number = %u", numberWithLocalOrdering);
            bytes += sizeof(uint32_t);
            length -= sizeof(uint32_t);
            // Do whatever you need to with the number
        }
    }
    

    Define your own internal structs and cast the pointer to it:

    NSData* data;
    struct headerType
    {
        uint16_t type;
        uint32_t length;
    
    };
    const struct headerType* header=(const struct headerType*)[data bytes]; // get the header of the response
    if (header->type==1)
    {
        const char* text=((const char*)header)+6; // skip the header (16bits+32bits=6 bytes offset)
    }
    

    EDIT:
    If you need to read them in a loop:

    NSData* data;
    const uint8_t* cursor=(const uint8_t*)[data bytes];
    while (true)
    {
        uint16_t type=*((uint16_t*)cursor);
        cursor+=2;
        if (cursor==1)
        {
            // string
            uint32_t length=*((uint32_t*)cursor);
            cursor+=4;
            const char* str=(const char*)cursor;
            cursor+=length;
        }
        else if (cursor==2)
        {
            // another type
        }
        else
            break;
    }