Crash with Stepper on MacOS

I tried to write a simple view with a stepper, but it immediatly crashes on MacOS if I hover the mouse over the stepper in in NSHostingView.hoverRegionIdentifier(for:) ()


struct ContentView: View {

var body: some View {

Stepper(onIncrement: { print("Inc") }, onDecrement: { print("Dec") }, label: { Text("Stepper") })

.frame(maxWidth: .infinity, maxHeight: .infinity)

}

}


Is there something wrong or it is a bug in SwiftUI?


I even tried to write my own view with NSViewRepresentable


struct MyStepper: NSViewRepresentable {

func updateNSView(_ nsView: NSView, context: NSViewRepresentableContext<MyStepper>) {


}

func makeNSView(context: Context) -> NSView {

return NSStepper(frame: .zero)

}

}


struct ContentView: View {

var body: some View {

MyStepper()

.frame(maxWidth: .infinity, maxHeight: .infinity)

}

}


Same problem.

Replies

Same here. It has been happening since beta4. Before that the Stepper() view worked fine.

FWIW, if you make an empty subclass of NSStepper and use that from your custom NSViewRepresentable, then it seems to work without crashing on hover. E.g.:


class MyStepper : NSStepper { }


Of course, you'll have to implement the bindings support yourself, but at least it is a temporary workaround until this weird bug is fixed.

Did you post a bug report with this workaround ? That could help speed up resolution.

With Catalina Beta 6 and Xcode 11 Beta 6 the problem still exists. I filed a bug report, but as most of you know, they will be ignored.

I found a workaround with which I am able to write at least simple demos.


class BugfixView: NSView {
    override func mouseEntered(with event: NSEvent) {
    }
   
    override func mouseExited(with event: NSEvent) {
    }
}


        do {
            let mySelector: Selector = #selector(NSResponder.mouseEntered(with:))
            let method: Method = class_getInstanceMethod(NSHostingView<ContentView>.self, mySelector)!
            let swizzledMethod: Method = class_getInstanceMethod(BugfixView.self, mySelector)!
            method_exchangeImplementations(method, swizzledMethod)
        }
        do {
            let mySelector: Selector = #selector(NSResponder.mouseExited(with:))
            let method: Method = class_getInstanceMethod(NSHostingView<ContentView>.self, mySelector)!
            let swizzledMethod: Method = class_getInstanceMethod(BugfixView.self, mySelector)!
            method_exchangeImplementations(method, swizzledMethod)
        }

Clever hack! It turns out that you can just do this, and it seems to work around the crash as well:


public extension NSStepper {
    override func mouseEntered(with event: NSEvent) {
        // prevents crash in SwiftUI via NSHostingView.hoverRegionIdentifier
    }

    override func mouseExited(with event: NSEvent) {
        // prevents crash in SwiftUI via NSHostingView.hoverRegionIdentifier
    }
}

Seems to be fixed now in Beta 7.