[quote='824638022, DTS Engineer, /thread/773326?answerId=824638022#824638022']
Create a no-copy DispatchData with the init(bytesNoCopy:deallocator:) initialiser. If you pass the .custom(…) deallocator, you get called back when it’s safe to free the memory.
IMPORTANT Your current approach, which relies on send completion callbacks, is incorrect and could lead to subtle memory corruption bugs.
[/quote]
Hi @DTS Engineer ,
I'm trying to use the DispatchData initializer with bytesNoCopy and a custom deallocator, as you suggested above. However, when I try the following code, I encounter a build error: "No exact matches in call to initializer". Below is the code I'm using:
let serial_dispatch = DispatchQueue(label: "com.custom.serial.queue")
let bhagavadGitaExcerpt = """
Your right is to perform your duty only, but never to its fruits. Let not the fruits of action be your motive, nor let your attachment be to inaction.
"""
let oneString = String(repeating: bhagavadGitaExcerpt, count: 1024 / bhagavadGitaExcerpt.count)
if let utf8Data = oneString.data(using: .utf8) {
let rawPointer = UnsafeMutableRawPointer(mutating: utf8Data.withUnsafeBytes { $0.baseAddress! })
let dispatchData = DispatchData(bytesNoCopy: rawPointer, deallocator: .custom (serial_dispatch, {
print("Data is safe to de-allocate")
})
}
I am using macOS Sonoma (14.5 and 14.2.1), and it seems that the init(bytesNoCopy:deallocator:) initializer is not available. Can someone confirm if this initializer is exposed to public API or if there's a different way to use DispatchData with no-copy functionality?
Also,
When I am using Data with bytesNoCopy and a custom deallocator in my code, even though I receive the send completion callbacks, the deallocator is never called. I have verified that the data is actually being delivered to another machine (checked using Wireshark), but the deallocator doesn't seem to be triggered.
import Foundation
import Network
var connect = NWConnection(host: "10.20.5.190", port: NWEndpoint.Port(rawValue: 28000)!, using: .udp)
connect.stateUpdateHandler = { state in
print ("Connection did change state: \(state)")
}
let bhagavadGitaExcerpt = """
Your right is to perform your duty only, but never to its fruits. Let not the fruits of action be your motive, nor let your attachment be to inaction.
"""
let oneMBString = String(repeating: bhagavadGitaExcerpt, count: 1024 / bhagavadGitaExcerpt.count)
let utf8Data = oneMBString.cString(using: .utf8)!
let data = Data(bytesNoCopy: UnsafeMutableRawPointer(mutating: utf8Data),
count: utf8Data.count,
deallocator: .custom({ ptr, size in
print ("Data is safe to de-allocate")
}))
for i in 1...1000 {
connect.send(content: data, completion: NWConnection.SendCompletion.contentProcessed({ error in
print ("Send \(i) completed with error code \(error?.errorCode)")
}))
}
let serial_dispatch = DispatchQueue(label: "com.custom.serial.queue")
connect.start(queue: serial_dispatch)
RunLoop.main.run()
Could you help me understand why the deallocator isn't being triggered in this case? Is there something in the Data or NWConnection lifecycle that I might be overlooking?
Topic:
App & System Services
SubTopic:
Networking
Tags: