How to convert Int to byte array of 4 bytes in Swift?
In Java an integer is always 32-bit, but in Swift it can be 32-bit or 64-bit, depending on the platform. Your code creates a byte array with the same size as that of the Int
type, on a 64-bit platform that are 8 bytes.
If you want to restrict the conversion to 32-bit integers then use Int32
instead of Int
, the result will then be an array of 4 bytes, independent of the platform.
An alternative conversion method is
let value: Int32 = -1333
let array = withUnsafeBytes(of: value.bigEndian, Array.init)
print(array) // [255, 255, 250, 203]
Or as a generic function for integer type of all sizes:
func byteArray<T>(from value: T) -> [UInt8] where T: FixedWidthInteger {
withUnsafeBytes(of: value.bigEndian, Array.init)
}
Example:
print(byteArray(from: -1333)) // [255, 255, 255, 255, 255, 255, 250, 203]
print(byteArray(from: Int32(-1333))) // [255, 255, 250, 203]
print(byteArray(from: Int16(-1333))) // [250, 203]
Convert Int to Array of UInt8 in swift
You could do it this way:
let x: Int = 2019
let length: Int = 2 * MemoryLayout<UInt8>.size //You could specify the desired length
let a = withUnsafeBytes(of: x) { bytes in
Array(bytes.prefix(length))
}
let result = Array(a.reversed()) //[7, 227]
Or more generally, we could use a modified version of this snippet:
func bytes<U: FixedWidthInteger,V: FixedWidthInteger>(
of value : U,
to type : V.Type,
droppingZeros: Bool
) -> [V]{
let sizeInput = MemoryLayout<U>.size
let sizeOutput = MemoryLayout<V>.size
precondition(sizeInput >= sizeOutput, "The input memory size should be greater than the output memory size")
var value = value
let a = withUnsafePointer(to: &value, {
$0.withMemoryRebound(
to: V.self,
capacity: sizeInput,
{
Array(UnsafeBufferPointer(start: $0, count: sizeInput/sizeOutput))
})
})
let lastNonZeroIndex =
(droppingZeros ? a.lastIndex { $0 != 0 } : a.indices.last) ?? a.startIndex
return Array(a[...lastNonZeroIndex].reversed())
}
let x: Int = 2019
bytes(of: x, to: UInt8.self, droppingZeros: true) // [7, 227]
bytes(of: x, to: UInt8.self, droppingZeros: false) // [0, 0, 0, 0, 0, 0, 7, 227]
How to convert a double into a byte array in swift?
typealias Byte = UInt8
func toByteArray<T>(var value: T) -> [Byte] {
return withUnsafePointer(&value) {
Array(UnsafeBufferPointer(start: UnsafePointer<Byte>($0), count: sizeof(T)))
}
}
toByteArray(1729.1729)
toByteArray(1729.1729 as Float)
toByteArray(1729)
toByteArray(-1729)
But the results are reversed from your expectations (because of endianness):
[234, 149, 178, 12, 177, 4, 155, 64]
[136, 37, 216, 68]
[193, 6, 0, 0, 0, 0, 0, 0]
[63, 249, 255, 255, 255, 255, 255, 255]
Added:
func fromByteArray<T>(value: [Byte], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
return UnsafePointer<T>($0.baseAddress).memory
}
}
let a: Double = 1729.1729
let b = toByteArray(a) // -> [234, 149, 178, 12, 177, 4, 155, 64]
let c = fromByteArray(b, Double.self) // -> 1729.1729
For Xcode8/Swift3.0:
func toByteArray<T>(_ value: T) -> [UInt8] {
var value = value
return withUnsafePointer(to: &value) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<T>.size) {
Array(UnsafeBufferPointer(start: $0, count: MemoryLayout<T>.size))
}
}
}
func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
$0.baseAddress!.withMemoryRebound(to: T.self, capacity: 1) {
$0.pointee
}
}
}
For Xcode8.1/Swift3.0.1
func toByteArray<T>(_ value: T) -> [UInt8] {
var value = value
return withUnsafeBytes(of: &value) { Array($0) }
}
func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBytes {
$0.baseAddress!.load(as: T.self)
}
}
Swift 4 convert bytes to Int and ntohl
The C int
type is a 32-bit integer (on all current Apple platforms),
whereas the Swift Int
is 64-bit integer on 64-bit platforms.
Therefore in Swift you'll have to use UInt32
for 32-bit integers:
var msgLength = (inputBuffer.bytes).load(as: UInt32.self)
msgLength = UInt32(bigEndian: msgLength)
Or, if you switch from NSData
to Data
:
let msgLength = UInt32(bigEndian:inputBuffer.withUnsafeBytes { $0.pointee })
(Even in the C code uint32_t
would be better suited than int
to emphasize that 4 bytes are read.)
How to convert NSDecimalNumber to byte array if NSDecimalNumber is bigger than Uint64?
The problem is obviously the use of uint64Value
, which obviously cannot represent any value greater than UInt64.max
, and your example, 59,785,897,542,892,656,787,456, is larger than that.
If you want to grab the byte representations of the 128 bit mantissa, you can use _mantissa
tuple of UInt16
words of Decimal
, and convert them to bytes if you want. E.g.
extension Decimal {
var byteArray: [UInt8] {
return [_mantissa.0,
_mantissa.1,
_mantissa.2,
_mantissa.3,
_mantissa.4,
_mantissa.5,
_mantissa.6,
_mantissa.7]
.flatMap { [UInt8($0 & 0xff), UInt8($0 >> 8)] }
}
}
And
if let foo = Decimal(string: "59785897542892656787456") {
print(foo.byteArray)
}
Returning:
[0, 0, 0, 0, 0, 0, 0, 0, 169, 12, 0, 0, 0, 0, 0, 0]
This, admittedly, only defers the problem, breaking the 64-bit limit of your uint64Value
approach, but is still constrained to the inherent 128-bit limit of NSDecimalNumber
/Decimal
. To capture numbers greater than 128 bits, you'd need a completely different representation.
NB: This also assumes that the exponent is 0
. If, however, you had some large number, e.g. 4.2e101 (4.2 * 10101), the exponent will be 100
and the mantissa will simply be 42
, which I bet is probably not what you want in your byte array. Then again, this is an example of a number that is too large to represent as a single 128 bit integer, anyway:
if let foo = Decimal(string: "4.2e101") {
print(foo.byteArray)
print(foo.exponent)
}
Yielding:
[42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
100
How to convert an ContiguousArray of Floats into a byte array in Swift?
You can use the withUnsafeBytes()
method to get a buffer pointer to the underlying bytes of the array's contiguous storage, and directly initialize an [UInt8]
array from that buffer pointer. Example:
let floatArray: [Float] = [1.0, 2.0]
// Works also with a ContiguousArray:
// let floatArray: ContiguousArray<Float> = [1.0, 2.0]
let byteArray = floatArray.withUnsafeBytes { Array($0) }
print(byteArray) // [0, 0, 128, 63, 0, 0, 0, 64]
Equivalently (based on Leo's suggestion):
let byteArray = floatArray.withUnsafeBytes(Array.init)
The byte array contains the binary representation of the floating point numbers in host byte order (which is little-endian on all current Apple platforms). A conversion to big-endian is possible, but not without an intermediate copy to an integer array:
let floatArray: ContiguousArray<Float> = [1.0, 2.0]
let intArray = floatArray.map { $0.bitPattern.bigEndian }
let byteArray = intArray.withUnsafeBytes(Array.init)
print(byteArray) // 63, 128, 0, 0, 64, 0, 0, 0]
Reverse conversion: A simple method would be
let floatArray2 = byteArray.withUnsafeBytes { Array($0.bindMemory(to: Float.self)) }
print(floatArray2) // [1.0, 2.0]
However, that requires that the element storage of the byte array is properly aligned for floating point numbers. If that is not guaranteed then you can do
var floatArray2 = [Float](repeating: 0.0, count: byteArray.count / MemoryLayout<Float>.stride)
_ = floatArray2.withUnsafeMutableBytes { byteArray.copyBytes(to: $0) }
print(floatArray2) // [1.0, 2.0]
How to change Java's byte to long in Swift
Assuming that Byte
is a type alias for UInt8
: You have to convert the bytes to Int
before shifting the values to the left, otherwise the result can overflow. This also helps the compiler to compile the expression successfully:
func setData(raw : [Byte]) {
mode_time = Int(raw[3] << 24) | Int(raw[2] << 16) | Int(raw[1] << 8) | Int(raw[0] << 0)
}
Note also that the Swift Int
type is platform dependent, it can be a 32-bit or a 64-bit integer, and on a 32-bit platform the above code an overflow if the result exceeds the maximal value of a signed integer. You might want to use UInt
, UInt32
, or Int64
instead. The latter is a 64-bit integer on all platforms, like Java's long
.
An alternative implementation is
func setData(raw : [Byte]) {
mode_time = raw.reversed().reduce(Int(0)) { ($0 << 8) + Int($1) }
}
if you don't feed more bytes than what fits into an Int
.
How to convert Swift Date into Byte Array?
You can create a method to convert FixedWidthInteger to bytes (big or little endian) for the year component, convert the other date componentes to bytes and append them to the result:
enum Endianness {
case big, little
}
extension FixedWidthInteger {
func data<D: DataProtocol & RangeReplaceableCollection>(
using endianness: Endianness = .big
) -> D {
withUnsafeBytes(of: endianness == .big ? bigEndian : littleEndian, D.init)
}
}
extension Calendar {
static let iso8601 = Self(identifier: .iso8601)
}
extension Date {
func component(_ component: Calendar.Component, using calendar: Calendar = .iso8601) -> Int {
calendar.component(component, from: self)
}
func data<D: DataProtocol & RangeReplaceableCollection>() -> D {
var dataProtocol: D = .init()
dataProtocol += UInt16(component(.year)).data() as D
dataProtocol.append(UInt8(component(.month)))
dataProtocol.append(UInt8(component(.day)))
dataProtocol.append(UInt8(component(.hour)))
dataProtocol.append(UInt8(component(.minute)))
dataProtocol.append(UInt8(component(.second)))
return dataProtocol
}
}
Usage:
let data: Data = Date().data()
print(Array(data))
This will print
[7, 230, 6, 17, 2, 10, 46]
Related Topics
Using "If Let" with Logical "Or" Operator
How to Connect Localhost (With Invalid Certificate) Using Alamofire
Swift - Get Nsbundle for Test Target
Core Data: Could Not Cast Value of Type 'Mytype_Mytype_2' to Mytype
Show Folder's Contents in Finder Using Swift
Use a Function to Find Common Elements in Two Sequences in Swift
How Are Optional Values Implemented in Swift
Swift Standard Documentation Comment
How to Instantiate a Storyboard from a File Within an iOS Playground
Insertion-Order Dictionary (Like Java's Linkedhashmap) in Swift
Swiftui .Rotationeffect() Framing and Offsetting
Skip Item When Performing Map in Swift
How to Move a Rotated Scnnode in Scenekit
How to Make Apple Sign in Revoke Token Post Request
Error Handling in Swift Does Not Involve Stack Unwinding. What Does It Mean