Convert hex data string to NSData in Objective C (cocoa)

后端 未结 9 1289
栀梦
栀梦 2020-12-03 11:55

fairly new iPhone developer here. Building an app to send RS232 commands to a device expecting them over a TCP/IP socket connection. I\'ve got the comms part down, and can s

相关标签:
9条回答
  • 2020-12-03 12:40

    Code for hex in NSStrings like "00 05 22 1C EA 01 00 FF". 'command' is the hex NSString.

    command = [command stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSMutableData *commandToSend= [[NSMutableData alloc] init];
    unsigned char whole_byte;
    char byte_chars[3] = {'\0','\0','\0'};
    for (int i = 0; i < ([command length] / 2); i++) {
        byte_chars[0] = [command characterAtIndex:i*2];
        byte_chars[1] = [command characterAtIndex:i*2+1];
        whole_byte = strtol(byte_chars, NULL, 16);
        [commandToSend appendBytes:&whole_byte length:1]; 
    }
    NSLog(@"%@", commandToSend);
    
    0 讨论(0)
  • 2020-12-03 12:51

    Here's an example decoder implemented on a category on NSString.

    #import <stdio.h>
    #import <stdlib.h>
    #import <string.h>
    
    unsigned char strToChar (char a, char b)
    {
        char encoder[3] = {'\0','\0','\0'};
        encoder[0] = a;
        encoder[1] = b;
        return (char) strtol(encoder,NULL,16);
    }
    
    @interface NSString (NSStringExtensions)
    - (NSData *) decodeFromHexidecimal;
    @end
    
    @implementation NSString (NSStringExtensions)
    
    - (NSData *) decodeFromHexidecimal;
    {
        const char * bytes = [self cStringUsingEncoding: NSUTF8StringEncoding];
        NSUInteger length = strlen(bytes);
        unsigned char * r = (unsigned char *) malloc(length / 2 + 1);
        unsigned char * index = r;
    
        while ((*bytes) && (*(bytes +1))) {
            *index = strToChar(*bytes, *(bytes +1));
            index++;
            bytes+=2;
        }
        *index = '\0';
    
        NSData * result = [NSData dataWithBytes: r length: length / 2];
        free(r);
    
        return result;
    }
    
    @end
    
    0 讨论(0)
  • 2020-12-03 12:51

    This is an old topic, but I'd like to add some remarks.

    • Scanning a string with [NSString characterAtIndex] is not very efficient. Get the C string in UTF8, then scan it using a *char++ is much faster.

    • It's better to allocate NSMutableData with capacity, to avoid time consuming block resizing. I think NSData is even better ( see next point )

    • Instead of create NSData using malloc, then [NSData dataWithBytes] and finally free, use malloc, and [NSData dataWithBytesNoCopy:length:freeWhenDone:]

    It also avoids memory operation ( reallocate, copy, free ). The freeWhenDone boolean tells the NSData to take ownership of the memory block, and free it when it will be released.

    • Here is the function I have to convert hex strings to bytes blocks. There is not much error checking on input string, but the allocation is tested.

    The formatting of the input string ( like remove 0x, spaces and punctuation marks ) is better out of the conversion function. Why would we lose some time doing extra processing if we are sure the input is OK.

    +(NSData*)bytesStringToData:(NSString*)bytesString
    {
        if (!bytesString || !bytesString.length) return NULL;
        // Get the c string
        const char *scanner=[bytesString cStringUsingEncoding:NSUTF8StringEncoding];
        char twoChars[3]={0,0,0};
        long bytesBlockSize = formattedBytesString.length/2;
        long counter = bytesBlockSize;
        Byte *bytesBlock = malloc(bytesBlockSize);
        if (!bytesBlock) return NULL;
        Byte *writer = bytesBlock;
        while (counter--) {
            twoChars[0]=*scanner++;
            twoChars[1]=*scanner++;
            *writer++ = strtol(twoChars, NULL, 16);
        }
        return[NSData dataWithBytesNoCopy:bytesBlock length:bytesBlockSize freeWhenDone:YES];
    }
    
    0 讨论(0)
提交回复
热议问题