我一直在探索 SwiftUI 的
onDrag
修饰符,但当它结束时似乎没有任何反馈这一事实让我有点困惑。有些人建议对 NSItemProvider
的 deinit
进行接线和操作,这解决了一些情况,但有一种情况特别不能解决,因为 SwiftUI 似乎正在泄漏 NSItemProvider
实例。这是重现该问题的最小设置:
import SwiftUI
struct DragDropDebugView: View {
@State private var isDragging = false
var body: some View {
VStack {
Text(isDragging ? "Dragging" : "Not dragging")
Color.red
.onDrag(
{
isDragging = true
return DraggableItemProvider {
self.isDragging = false
}
},
preview: {
Color.blue.frame(width: 50, height: 50)
}
)
}
}
}
private final class DraggableItemProvider: NSItemProvider {
private var deinitAction: () -> Void
init(deinitAction: @escaping () -> Void) {
print("DraggableItemProvider init")
self.deinitAction = deinitAction
super.init()
}
deinit {
print("DraggableItemProvider deinit")
deinitAction()
}
}
如果我长按触发拖动操作,拖动项目并释放,此设置可以正常工作,我可以看到
DraggableItemProvider deinit
正在打印。如果我只是长按并释放而不将其拖动,则永远不会打印 deinit
,我可以在内存图中看到泄漏的实例:
有人知道解决这个问题的方法吗?
我将可用 API 的意图解释如下:
=>
因此,接受这些限制,我们必须找到兼容的实现,或者完全找到另一个解决方案(即自定义拖动处理或库。)
这是一个简单、惯用的解决方案,其行为与您的尝试相似但不完全相同。
struct DragDropDebugView: View {
@State private var isDragActive = false
var body: some View {
VStack {
Text(isDragActive ? "Dragging" : "Not dragging")
Color.red
.draggable(Data())
}
.onDrop(of: [.data], isTargeted: $isDragActive) { _ in true }
}
}