1

I have an NSData object that is being allocated with bytes that are representing unsigned integers from 0-255. What is the simplest way to convert these bytes to integers, or, if it is easier, to a string/NSString?

For instance, if I have bytes 0x00, 0x02, and 0x0A in my NSData object, then I would like to have either an integer array of {0,2,10} or the string/NSString "0210".

It seems that there are plenty of ways to turn NSData into ASCII NSStrings,UInt8 arrays, etc, but I cannot for the life of me figure out how to do this simple conversion in Swift.

Edit: Example Code of what I want:

var data:NSData
/*allocate NSData*/
var unsignedInts = [Int]()
/*Allocate each byte of data to an individual index of unsignedInts */
print(unsignedInts)
//should see {0, 1, 10} if bytes are 0x00, 0x01, and 0x0A
1

2 Answers 2

2

It is necessary to create a new Array of Int because Int require more bytes per entry.

var nsData: NSData = NSData(bytes: [0x00, 0x02, 0x0A] as [UInt8], length: 3)
let buffer = UnsafeBufferPointer<UInt8>(start:UnsafePointer<UInt8>(nsData.bytes), count:nsData.length)
print("nsData: \(nsData)")

var intData = [Int]()
intData.reserveCapacity(nsData.length)

var stringData = String()

for i in 0..<nsData.length {
    intData.append(Int(buffer[i]))
    stringData += String(buffer[i])
}

print("intData: \(intData)")
print("stringData: \(stringData)")

nsData: <00020a>
intData: [0, 2, 10]
stringData: 0210

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your time @zaph, much appreciated.
This isn't very efficient, as the intArray and stringData has to allocate new memory a lot.. You should use reserveCapacity to avoid that
@zaph Better, but reserveCapacity doesn't take the amount of bytes, but rather the amount of elements (the sizeofs aren't needed). Also the string actually needs about 2-3 times more elements, as the string of a UInt8 can range from "0" (1 char) to "256" (3 chars), a factor of 3 should do. If you want the math: 10/256 prob of 1 char, 90/256 prob of 2 chars, 156/256 prob of 3 chars gives a factor of about 2.57 (assuming a random distribution), which would give stringData.reserveCapacity(Int(Double(nsData.length) * 2.57))). Of course this is just a detail, append isn't that bad anyways
@Kametrixom thanks for the information and yes, I totally missed considering the size needed for a string representation of a byte. I have removed the reserveCapacity for the string as it affods minimmal improvement (< 1us) and adds complexity.
0

I can recommend a method like this:

import Foundation

extension NSData {
    var byteBuffer : UnsafeMutableBufferPointer<UInt8> {
        return UnsafeMutableBufferPointer(start: UnsafeMutablePointer(bytes), count: length)
    }

    var array : [UInt8] {
        return Array(byteBuffer)
    }

    var intArray : [Int] {
        return byteBuffer.map(Int.init)
    }

    var byteString : String {
        return byteBuffer.lazy.map(String.init).joinWithSeparator("")
    }
}

Usage:

let data1 = NSData(bytes: [0x48, 0xa1, 0x95, 0xe, 0x1c, 0x38, 0x82] as [UInt8], length: 7)       // <48a1950e 1c3882>

print(data1.array)       // "[72, 161, 149, 14, 28, 56, 130]"
print(data1.intArray)    // "[72, 161, 149, 14, 28, 56, 130]"
print(data1.byteString)  // "72161149142856130"

let data2 = NSData(bytes: [0x00, 0x02, 0x0A] as [UInt8], length: 3)

print(data2.array)       // "[0, 2, 10]"
print(data2.intArray)    // "[0, 2, 10]"
print(data2.byteString)  // "0210"

It's very easy, Swift-y and efficient like this.

Note that in some cases you don't actually need an array like this, because you can just access all the values of the data in the same way without allocating a new array (recommended):

data1.byteBuffer[4]      // 28
data1.byteBuffer.count   // 7
data1.byteBuffer(14)     // 3

EDIT: I added a property that returns an Int array, although I can't see a reason you'd need it

7 Comments

@zaph I edited my answer, although that's not really a reason to downvote imho
@zaph btw have a look at what it says when you hover over the downvote button: "This answer is not useful" -> Downvotes aren't for answers that don't 100% answer the original question
It does seem you have a really good grasp of Swift and the answer provides a correct answer but I disagree with the solution. IMO the solution is horrible.
@zaph Why do you disagree? I just chose the more functional way (in Swift's spirit) of doing it and you chose the imperative way
If you want to chat about why let me know.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.