简体   繁体   中英

Read NSNumber from NSData

I pretty new to Objective-C (and C itself) and need to consume a NSData from a HTTP output. I've never really worked with byte arrays or had to worry about little/big endian issues, and have struggled a bit to write the following method to read a NSNumber with a specified length from that NSData .

- (NSNumber *)readNumberWithLength:(NSUInteger)length
{
    Byte k[length];
    [data getBytes:k range:NSMakeRange(offset, length)]; // big endian byte array representing a number
    offset += length;

    NSNumber *number;
    if (length==4) {
        number = [NSNumber numberWithUnsignedInt:CFSwapInt32BigToHost(*(uint32_t *)k)];
    } else if (length==2) {
        number = [NSNumber numberWithUnsignedShort:CFSwapInt16BigToHost(*(uint16_t *)k)];
    } else if (length==1) {
        number = [NSNumber numberWithUnsignedChar:*(uint8_t *)k];
    } else if (length==8) {
        number = [NSNumber numberWithUnsignedLongLong:CFSwapInt64BigToHost(*(uint64_t *)k)];
    } else {
        number = [NSNumber numberWithInt:0];
    }

    return number;
}

I have NSData *data and NSUInteger offset declared as instance variables.

Is this code correct? Is there anything I should worry about? I haven't tested it on an actual device yet (only on the Simulator) and it seems to be working fine for me. Do you have any comments on it?

Thank you!

The code looks more or less correct.

Seems like the hard way.

I would be surprised -- not totally shocked, but surprised -- that the data coming back from the HTTP server is really just raw bytes. It would be exceptionally rare that it is and, in the case that it is, the design of the server is almost assuredly wrong. (There are certainly cases where binary-HTTP-response is the right answer, but it is very very rare).

Unless you are talking about 100s of thousands of values in the data, the overhead implied by HTTP is almost certainly going to outweigh any gains of going binary. Parsing known numeric values from a string isn't that onerous unless you are truly doing this constantly (which would make using HTTP not particularly attractive in the first place).


Server design: fair enough. Another valid reason to deal with it is because you can't change that particular piece of the puzzle.

I would personally implement the code more defensively:

  • validate that the local data sizes are of the expected sizes compared to the remote / network sizes to prevent surprises (this could be assertions on initialization or in some debug code -- I prefer being über defensive in situations like these).

  • use a case statement instead of the if/else if/else if/else sequence. Completely an aesthetic decision, but it would contribute to...

  • ... deal with the length being an unexpected value by logging, even if only in debug mode. I would think an unexpected value size would be potentially very bad for overall correctness?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM