I have a 60 byte Data
stream as follows
let myDataStream = Data(bytes: [24, 163, 209, 194, 255, 1, 184, 230, 37, 208, 140, 201, 6, 0, 64, 0, 7, 98, 108, 117, ...])
Byte #1 (index 0) represents represent the length of the first object, so in this case the first object is comprised of the first 24 objects including byte #1
I have tried numerous methods but I have been unable to figure out
How to extract the first 24 bytes into a new Data object
How to remove the first 24 bytes from myDataStream
once #1 has been accomplished. As byte #25 will again have size of next object
The closest I have come to solving #1 is
let streamLength = Int(myDataStream[0])
let newStream = Data(bytes: myDataStream[0...streamLength])
but I get an error stating cannot invoke initializer for Data with Data.subsequence
You can utilize a combination of the subdata
and removeSubRange
methods to achieve your desired results.
subData(in:)
is an instance method on a Data
struct.
removeSubRange()
is also an instance method on a Data
struct.
You can read more about these methods here: https://developer.apple.com/reference/foundation/data
Example Method:
func extract(from data: inout Data) -> Data? {
guard data.count > 0 else {
return nil
}
// Define the length of data to return
let length = Int.init(data[0])
// Create a range based on the length of data to return
let range = Range(0..<length)
// Get a new copy of data
let subData = data.subdata(in: range)
// Mutate data
data.removeSubrange(range)
// Return the new copy of data
return subData
}
Usage:
// Data (27 bytes)
var data = Data(bytes: [24, 163, 209, 194, 255, 1, 184, 230, 37, 208, 140, 201, 6, 0, 64, 0, 7, 98, 108, 117, 42, 63, 78, 200, 3, 34, 36])
// First extraction
let first = extract(from: &data)
print(first!) // Prints 24 bytes
print(data) // Prints 3 bytes
// Second extraction
let second = extract(from: &data)
print(second!) // Prints 3 bytes
print(data) // Prints 0 bytes
// Third extraction
let third = extract(from: &data)
print(third ?? "No Data") // Prints "No Data"
Making an Extension
You could also wrap the extract
method above in an extension of Data
as follows:
extension Data {
mutating func extract() -> Data? {
guard self.count > 0 else {
return nil
}
// Define the length of data to return
let length = Int.init(self[0])
// Create a range based on the length of data to return
let range = Range(0..<length)
// Get a new copy of data
let subData = self.subdata(in: range)
// Mutate data
self.removeSubrange(range)
// Return the new copy of data
return subData
}
}
Then you could you use the method like this:
// Data (27 bytes)
var data = Data(bytes: [24, 163, 209, 194, 255, 1, 184, 230, 37, 208, 140, 201, 6, 0, 64, 0, 7, 98, 108, 117, 42, 63, 78, 200, 3, 34, 36])
// First extraction
let first = data.extract()
print(first!) // Prints 24 bytes
print(data) // Prints 3 bytes
// Second extraction
let second = data.extract()
print(second!) // Prints 3 bytes
print(data) // Prints 0 bytes
// Third extraction
let third = data.extract()
print(third ?? "No Data") // Prints "No Data"
Data
has dedicated functions to handle subdata
:
let streamLength = Int(myDataStream[0])
let newStream = myDataStream.subdata(in: 1..<streamLength + 1)
let nextStream = myDataStream.subdata(in: streamLength + 1..<myDataStream.count)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With