我正在研究如何从DispatchData
实例中创建Data
实例。我开始使用静态函数:
static func dispatchData(fromData data: Data) -> DispatchData {
return data.withUnsafeBytes { (typedPtr: UnsafePointer<UInt8>) -> DispatchData in
let bufferPtr = UnsafeRawBufferPointer(start: UnsafeRawPointer(typedPtr), count: data.count)
return DispatchData(bytes: bufferPtr)
}
}
这很好(并且恰巧与this answer非常相似)。然后我决定将其作为初始化程序添加到扩展名中的DispatchData
并写道:
private extension DispatchData {
init(data: Data) {
data.withUnsafeBytes { (typedPtr: UnsafePointer<UInt8>) in // 1
let bufferPtr = UnsafeRawBufferPointer(start: UnsafeRawPointer(typedPtr), count: data.count)
self.init(bytes: bufferPtr)
}
}
}
此时,编译器拒绝标记为// 1
:
在初始化之前由闭包捕获的变量'self .__ wrapped'
这是有道理的 - 编译器不希望在我委托给self
之前捕获init(bytes: UnsafeRawBufferPointer)
,因为存储的变量 - 如__wrapped
,在这种情况下 - 不是'尚未初始化。但我看不出另一种获得UnsafeRawBufferPointer
的方式;根据{{3}}:
data.withUnsafeBytes
返回
警告
不应在闭包调用的生命周期之外存储和使用字节指针参数。
我知道我可以回到使用静态函数来实现我想要的东西,但如果有办法添加这个初始化程序,我更喜欢它。有没有办法让这个初始化程序按预期工作?
答案 0 :(得分:3)
你的扩展的问题在于,尽管编译器知道你将关闭作为非转义参数传递给withUnsafeBytes(_:)
;它没有任何保证它将被调用一次而仅一次(这是初始化所必需的。)
一个简单的解决方案是,而不是链接到另一个初始化器,只需自己构造一个DispatchData
的新实例,然后将其分配给self
,从而完成初始化:
import Foundation
private extension DispatchData {
init(data: Data) {
self = data.withUnsafeBytes { (typedPtr: UnsafePointer<UInt8>) in
DispatchData(bytes:
UnsafeRawBufferPointer(start: typedPtr, count: data.count)
)
}
}
}
另请注意,将UnsafePointer<UInt8>
传递给UnsafeRawPointer?
时,会将其作为参数传递;所以我们不需要将它包装在初始化调用中。
在Swift 5中,withUnsafeBytes
直接为您提供UnsafeRawBufferPointer
:
private extension DispatchData {
init(data: Data) {
self = data.withUnsafeBytes(DispatchData.init)
}
}