here is a minimal reproducible example, on macOS
struct ContextMenuTest1: View {
@State var visible: Bool = true
var body: some View {
Button(action: { self.visible.toggle() }, label: { Text("ContextMenuTest2 Toggle") })
if self.visible {
ChildView()
}
}
struct ChildView: View {
class Model: ObservableObject {
init() {
print("Model Created")
}
deinit {
print("This will never be called")
}
func someAction() {
}
}
var body: some View {
Text("Text That has Context Menu")
.contextMenu {
ContextMenu()
}
}
struct ContextMenu: View {
@StateObject var model: Model = .init()
var body: some View {
Button(action: {
self.model.someAction()
}, label: {
Text("Context Menu Button 1")
})
}
}
}
}
step to reproduce :
- right click on Text("Text That has Context Menu") to open contextMenu()
- turn off the contextMenu
- click "ContextMenuTest2 Toggle"
This should have destroyed both ChildView and ChildView.ContextMenu, thus should have deallocated ChildView.Model but ChildView.Model.deinit never be called.
I understand .contextMenu() document show examples of putting Button directly, but it doesn't mention or block attempts of putting custom view directly like this - in which case, Button.action closure it permanent memory leaked. unless you kill the application
hope that clairify the bug, thanks!