I'm trying to convert this Objective-C code (originally found in this Stack Overflow question) which turns an NSString
into NSData
to Swift:
- (NSData *)dataFromHexString { const char *chars = [self UTF8String]; int i = 0, len = self.length; NSMutableData *data = [NSMutableData dataWithCapacity:len / 2]; char byteChars[3] = {'\0','\0','\0'}; unsigned long wholeByte; while (i < len) { byteChars[0] = chars[i++]; byteChars[1] = chars[i++]; wholeByte = strtoul(byteChars, NULL, 16); [data appendBytes:&wholeByte length:1]; } return data; }
My first pass looked like this:
func hexStringToBytes(hexString: String) -> NSData? {
guard let chars = hexString.cStringUsingEncoding(NSUTF8StringEncoding) else { return nil}
var i = 0
let length = hexString.characters.count
let data = NSMutableData(capacity: length/2)
var byteChars: [CChar] = [0, 0, 0]
var wholeByte = CUnsignedLong()
while i < length {
byteChars[0] = chars[i++]
byteChars[1] = chars[i++]
i+=1
wholeByte = strtoul(byteChars, nil, 16)
data?.appendBytes(&wholeByte, length: 1)
}
return data
}
I realized I could optimize this further, since ++
is deprecated and will be removed in Swift 3:
func hexStringToBytes(hexString: String) -> NSData? {
guard let chars = hexString.cStringUsingEncoding(NSUTF8StringEncoding) else { return nil}
var i = 0
let length = hexString.characters.count
let data = NSMutableData(capacity: length/2)
var byteChars: [CChar] = [0, 0, 0]
var wholeByte: CUnsignedLong = 0
while i < length {
byteChars[0] = chars[i]
i+=1
byteChars[1] = chars[i]
i+=1
wholeByte = strtoul(byteChars, nil, 16)
data?.appendBytes(&wholeByte, length: 1)
}
return data
}
And then as an extension on String:
extension String {
func dataFromHexString() -> NSData? {
guard let chars = cStringUsingEncoding(NSUTF8StringEncoding) else { return nil}
var i = 0
let length = characters.count
let data = NSMutableData(capacity: length/2)
var byteChars: [CChar] = [0, 0, 0]
var wholeByte: CUnsignedLong = 0
while i < length {
byteChars[0] = chars[i]
i+=1
byteChars[1] = chars[i]
i+=1
wholeByte = strtoul(byteChars, nil, 16)
data?.appendBytes(&wholeByte, length: 1)
}
return data
}
}
A few questions:
How can I optimize the ugly
i+=1
lines?Is
cStringUsingEncoding(NSUTF8StringEncoding)
the correct way to get the[CChar]
from the string?Since this is almost a direct translation from Objective-C, is there any way to make this more "Swifty," say by using
map
orstride
, without sacrificing speed?