How to convert an Int into NSData in Swift?
Solution 1
With Swift 3.x to 5.0:
var myInt = 77
var myIntData = Data(bytes: &myInt,
count: MemoryLayout.size(ofValue: myInt))
Solution 2
In contemporary versions of Swift, I would do:
let score = 1000
let data = withUnsafeBytes(of: score) { Data($0) }
e8 03 00 00 00 00 00 00
And convert that Data
back to an Int
:
let value = data.withUnsafeBytes {
$0.load(as: Int.self)
}
Note, when dealing with binary representations of numbers, especially when exchanging with some remote service/device, you might want to make the endianness explicit, e.g.
let data = withUnsafeBytes(of: score.littleEndian) { Data($0) }
e8 03 00 00 00 00 00 00
And convert that Data
back to an Int
:
let value = data.withUnsafeBytes {
$0.load(as: Int.self).littleEndian
}
Versus big endian format, also known as “network byte order”:
let data = withUnsafeBytes(of: score.bigEndian) { Data($0) }
00 00 00 00 00 00 03 e8
And convert that Data
back to an Int
:
let value = data.withUnsafeBytes {
$0.load(as: Int.self).bigEndian
}
Needless to say, if you don’t want to worry about endianness, you could use some established standard like JSON (or even XML).
For Swift 2 rendition, see previous revision of this answer.
Solution 3
For any integer type:
extension FixedWidthInteger {
var data: Data {
let data = withUnsafeBytes(of: self) { Data($0) }
return data
}
}
Example:
let data = 1.data
Solution 4
You can convert in this way:
var myScore: NSInteger = 0
let data = NSData(bytes: &myScore, length: sizeof(NSInteger))
Solution 5
Swift 5, add an other option.
NSData
is old, still effective
Write Data:
let buffer = NSMutableData()
let size = MemoryLayout<UInt>.size
let big = 1000
let small = 10
withUnsafeBytes(of: big, { (p) in
let bufferPointer = p.bindMemory(to: UInt.self)
if let address = bufferPointer.baseAddress{
buffer.append(address, length: size)
}
})
withUnsafeBytes(of: small, { (p) in
let bufferPointer = p.bindMemory(to: UInt.self)
if let address = bufferPointer.baseAddress{
buffer.append(address, length: size)
}
})
Read data:
if let d = buffer.copy() as? Data{
var big: UInt = 0
var small: UInt = 0
let size = MemoryLayout<UInt>.size
let meta = NSData(data: data)
meta.getBytes(&big, range: NSRange(location: 0, length: size))
meta.getBytes(&small, range: NSRange(location: size, length: size))
print("big:", big, "\nsmall:", small)
// big: 1000
// small: 10
}
You know the memory layout, the data put in the memory,
Then put them out exactly.
unsafe
method is funny
Cesare
Updated on July 17, 2022Comments
-
Cesare almost 2 years
In Objective-C I use the following code to
Convert an
Int
variable intoNSData
, a packet of bytes.int myScore = 0; NSData *packet = [NSData dataWithBytes:&myScore length:sizeof(myScore)];
Use the converted
NSData
variable into a method.[match sendDataToAllPlayers: packet withDataMode: GKMatchSendDataUnreliable error: &error];
I tried converting the Objective-C code into Swift:
var myScore : Int = 0 func sendDataToAllPlayers(packet: Int!, withDataMode mode: GKMatchSendDataMode, error: NSErrorPointer) -> Bool { return true }
However, I am not able to convert an
Int
variable into anNSData
and use it an a method. How can I do that? -
Cesare about 9 yearsThank you very much! May you please tell me how to include
data
into my method? I getdata is not a type
when I code it this way:func sendDataToAllPlayers(data,
-
David V about 9 yearsYou are welcome :) Sorry, I don't catch your question, what you need to do?
-
Cesare about 9 yearsIf you look at the second bullet point of my question there is a code of a function
sendDataToAllPlayers
Now, I translated that function already but I would like to include the constantdata
you have declared in your answer into my Swift method. Sorry for the misunderstanding! -
David V about 9 yearsIt seems that Rob's answer is what you are looking, is it true? of I'm missing something?
-
Drux about 9 yearsIMO such
data
won't be portable (should not be transferred without additional metadata) between devices with different byte orders (see here). -
Rob about 9 yearsI actually agree. I just modeled my answer after the sending data to other players discussion in the Game Center Programming Guide, but it does seem more prudent to use archive or plist or some other more robust format.
-
Benjohn about 7 yearsYou can use
score.bigEndian
orscore.littleEndian
to force the byte order to be of a specific endianness. The data will then be compatible between architectures able to be written on one and read on another. -
Benjohn about 7 yearsI'd suggest
bigEndian
, as this is generally considered to be "network byte order". And is also, obviously, the correct way around ;-) -
bojan almost 4 yearsData([UInt8(value)]) will only let you use numbers > 0 and < 256...
-
Brody Robertson almost 4 yearsNo doubt, that's why I qualified the answer.