Post

Replies

Boosts

Views

Activity

Reply to NSScrollView: Overriding "scrollWheel(with:)" can cause a never-ending live scroll
Hi @Etresoft and @DTS Engineer, thank you so much for your feedback and further testing. Fortunately, I stumbled across this jackpot in the old documentation: https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKitOlderNotes/#10_9Scrolling The relevant line is: Do not override -scrollWheel: in an NSScrollView, NSClipView subclass, or in the document view. Overriding scrollWheel(with:) in those places disables Responsive Scrolling. So, I removed the scrollWheel(with:) override from my NSScrollView subclass and added it to a subview of documentView instead. That solved the issue. I still think the original issue is a bug in NSScrollView, because a live scroll shouldn't get stuck even if Responsive Scrolling is disabled. I'll update FB25362729 with my findings.
Topic: UI Frameworks SubTopic: AppKit
5d
Reply to NSScrollView: Overriding "scrollWheel(with:)" can cause a never-ending live scroll
@Etresoft thanks for the insight. The reason I'm using scrollWheel(with:) rather than NSPanGestureRecognizer is because, as far as I'm aware, AppKit's NSPanGestureRecognizer can recognize drags but not scrolls (please correct me if I'm wrong). This is in contrast to UIKit's UIPanGestureRecognizer, which can recognize both drags and scrolls (by setting UIPanGestureRecognizer.allowedScrollTypesMask). In the UIKit version of my app, I implemented Option-zoom by adding a UIPanGestureRecognizer to UIScrollView and overriding UIView.gestureRecognizerShouldBegin(_:) to control whether my added UIPanGestureRecognizer or UIScrollView.panGestureRecognizer begins. I wish I could do the same in the AppKit version, but NSPanGestureRecognizer has no equivalent to UIPanGestureRecognizer.allowedScrollTypesMask. As for NSScrollView.willStartLiveScrollNotification and NSScrollView.didEndLiveScrollNotification, I don't actually use those for the Option-zoom. I use those mainly to enable/disable a separate zoom slider NSToolbarItem that's in NSWindow.toolbar, because I don't want the user to be able to simultaneously use the NSToolbarItem and the NSScrollView to scroll/zoom the canvas. This simultaneous use is possible when using Sidecar with NSViewGestureRecognizerIsExclusive set to NO (which is the case in my app). I hope that clarifies the whole story. You are much more experienced than me so I really appreciate your insight.
Topic: UI Frameworks SubTopic: AppKit
6d
Reply to NSScrollView: Overriding "scrollWheel(with:)" can cause a never-ending live scroll
Hi @DTS Engineer, thanks for your feedback. I tried the "override in the document view instead of the scroll view" variation too and didn't work for me either. And thank you for your workaround using a local event monitor. That's something I'll try. However, I'm not sure if determining isOverScrollView is enough. I guess I'll also need to keep track of if there is a popover/sheet/something else on top of the NSScrollView that should get priority. Nonetheless, it's a promising workaround. I still hope Apple will fix the actual bug in the override. I updated my report with your info that it's occurring on macOS 27.0.1 too.
Topic: UI Frameworks SubTopic: AppKit
6d
Reply to NSScrollView: Overriding "scrollWheel(with:)" can cause a never-ending live scroll
Hi @Etresoft, thanks for your feedback. I'm trying to implement Option-zoom like in Pixelmator Pro: If I hold Option and scroll up or down, it results in a zoom instead of a scroll. The Apple Maps app does something similar: If I hold Option and scroll up or down, it changes the pitch of the camera instead of scrolling. I already have Option-zoom implemented and working. It's just the live scroll getting stuck that's the issue. I updated my report with your info that it's occurring on Sequoia too.
Topic: UI Frameworks SubTopic: AppKit
6d
Reply to CATiledLayer flashes and re-draws entirely when re-drawing a single tile
I have not yet checked if the "redraws entire contents instead of specified rect" issue is still occurring. However, the "flashes on redraw" issue is still occurring with CATiledLayer in Xcode 26.6. The flash occurs even when returning 0 from CATiledLayer.fadeDuration(). It seems that each sublayer/tile of the CATiledLayer simply releases/erases its already-drawn contents before drawing the new contents. It would be nice to have the option to replace the existing drawing without erasing it first. This solution from @mgalijot: [quote='786127021, mgalijot, /thread/786127, /profile/mgalijot'] I have, however, found one interesting thing which seems to work so far: before calling setNeedsDisplayInRect (or just setNeedsDisplay, as they behave the same for CATiledLayer in my testing), cache the current layer's contents, and after calling setNeedsDisplay (or setNeedsDisplayInRect), restore the contents back to the layer. This prevents flashing and preserves any tiles that were drawn at the time of the re-draw. let c = tiledLayer.contents tiledLayer.setNeedsDisplay(tileRect) tiledLayer.contents = c [/quote] does fix the flash. Could an Apple engineer comment whether or not this is a valid workaround? Here's the relevant code I'm currently using (Swift 6): CATiledLayer subclass nonisolated final class NoFade_CATiledLayer: CATiledLayer { override class func fadeDuration() -> CFTimeInterval { 0 } } UIView layerClass override class var layerClass: AnyClass { NoFade_CATiledLayer.self } UIView draw(_:) /* This method must be marked "nonisolated" when it is called by "CATiledLayer" or one of its sublayers. Otherwise, the app crashes. */ nonisolated override func draw(_ rect: CGRect) { guard let cgContext = UIGraphicsGetCurrentContext() else { return } let cgPaths = cgPaths_Mutex.withLock { $0 } let fillColor = CGColor( srgbRed: 0.5, green: 0.5, blue: 0.5, alpha: 1 ) for cgPath in cgPaths { cgContext.addPath(cgPath) cgContext.setFillColor(fillColor) cgContext.fillPath() } } Calling setNeedsDisplay() private func onChange_cgPaths(newPaths: [CGPath]) { cgPaths_Mutex.withLock { (cgPaths: inout [CGPath]) -> Void in cgPaths = newPaths } setNeedsDisplay() }
Topic: UI Frameworks SubTopic: General Tags:
Jul ’26
Reply to SwiftData document-based app crashes on undo/redo without ModelContext.transaction(block:)
The issue is still occurring with Xcode 26.4.1 (17E202) and macOS Tahoe 26.4.1 (25E253). I also noticed that, rarely, the following errors get logged when the app crashes instead of the error in my original post: SwiftData.DefaultStore save failed with error: Error Domain=NSCocoaErrorDomain Code=1570 "%{PROPERTY}@ is a required value." UserInfo={NSValidationErrorObject=<NSManagedObject: 0x9da1b20d0> (entity: ChildItem; id: 0x9d7f324a0 <x-coredata:///ChildItem/tA0242788-AD81-4A4A-82BD-92796386C7E75>; data: { index = nil; parentItem = "0x9d7f32380 <x-coredata:///ParentItem/tA0242788-AD81-4A4A-82BD-92796386C7E73>"; }), NSLocalizedDescription=%{PROPERTY}@ is a required value., NSValidationErrorKey=index, NSValidationErrorValue=null} SwiftData/ModelContext.swift:3256: Fatal error: Illegal attempt to resolve a fault against a store that is not known to this model context: PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(backing: SwiftData.PersistentIdentifier.PersistentIdentifierBacking.managedObjectID(0x9d7f32380 <x-coredata:///ParentItem/tA0242788-AD81-4A4A-82BD-92796386C7E73>))) SwiftData.ModelContext Can't show source file for stack frame 8: ParentItem.childItems.getter The file path does not exist on the file system: /var/folders/sb/kvhs_53d49n1djmvf6jbf6lh0000gp/T/swift-generated-sources/@__swiftmacro_12DocumentTest10ParentItemC10childItems18_PersistedPropertyfMa_.swift However, I don't know how to reproduce these specific errors. They get logged randomly and rarely. Most of the time, the error in my original post gets logged.
Topic: App & System Services SubTopic: iCloud Tags:
Apr ’26
Reply to NSScrollView: Overriding "scrollWheel(with:)" can cause a never-ending live scroll
Hi @Etresoft and @DTS Engineer, thank you so much for your feedback and further testing. Fortunately, I stumbled across this jackpot in the old documentation: https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKitOlderNotes/#10_9Scrolling The relevant line is: Do not override -scrollWheel: in an NSScrollView, NSClipView subclass, or in the document view. Overriding scrollWheel(with:) in those places disables Responsive Scrolling. So, I removed the scrollWheel(with:) override from my NSScrollView subclass and added it to a subview of documentView instead. That solved the issue. I still think the original issue is a bug in NSScrollView, because a live scroll shouldn't get stuck even if Responsive Scrolling is disabled. I'll update FB25362729 with my findings.
Topic: UI Frameworks SubTopic: AppKit
Replies
Boosts
Views
Activity
5d
Reply to NSScrollView: Overriding "scrollWheel(with:)" can cause a never-ending live scroll
@Etresoft thanks for the insight. The reason I'm using scrollWheel(with:) rather than NSPanGestureRecognizer is because, as far as I'm aware, AppKit's NSPanGestureRecognizer can recognize drags but not scrolls (please correct me if I'm wrong). This is in contrast to UIKit's UIPanGestureRecognizer, which can recognize both drags and scrolls (by setting UIPanGestureRecognizer.allowedScrollTypesMask). In the UIKit version of my app, I implemented Option-zoom by adding a UIPanGestureRecognizer to UIScrollView and overriding UIView.gestureRecognizerShouldBegin(_:) to control whether my added UIPanGestureRecognizer or UIScrollView.panGestureRecognizer begins. I wish I could do the same in the AppKit version, but NSPanGestureRecognizer has no equivalent to UIPanGestureRecognizer.allowedScrollTypesMask. As for NSScrollView.willStartLiveScrollNotification and NSScrollView.didEndLiveScrollNotification, I don't actually use those for the Option-zoom. I use those mainly to enable/disable a separate zoom slider NSToolbarItem that's in NSWindow.toolbar, because I don't want the user to be able to simultaneously use the NSToolbarItem and the NSScrollView to scroll/zoom the canvas. This simultaneous use is possible when using Sidecar with NSViewGestureRecognizerIsExclusive set to NO (which is the case in my app). I hope that clarifies the whole story. You are much more experienced than me so I really appreciate your insight.
Topic: UI Frameworks SubTopic: AppKit
Replies
Boosts
Views
Activity
6d
Reply to NSScrollView: Overriding "scrollWheel(with:)" can cause a never-ending live scroll
Hi @DTS Engineer, thanks for your feedback. I tried the "override in the document view instead of the scroll view" variation too and didn't work for me either. And thank you for your workaround using a local event monitor. That's something I'll try. However, I'm not sure if determining isOverScrollView is enough. I guess I'll also need to keep track of if there is a popover/sheet/something else on top of the NSScrollView that should get priority. Nonetheless, it's a promising workaround. I still hope Apple will fix the actual bug in the override. I updated my report with your info that it's occurring on macOS 27.0.1 too.
Topic: UI Frameworks SubTopic: AppKit
Replies
Boosts
Views
Activity
6d
Reply to NSScrollView: Overriding "scrollWheel(with:)" can cause a never-ending live scroll
Hi @Etresoft, thanks for your feedback. I'm trying to implement Option-zoom like in Pixelmator Pro: If I hold Option and scroll up or down, it results in a zoom instead of a scroll. The Apple Maps app does something similar: If I hold Option and scroll up or down, it changes the pitch of the camera instead of scrolling. I already have Option-zoom implemented and working. It's just the live scroll getting stuck that's the issue. I updated my report with your info that it's occurring on Sequoia too.
Topic: UI Frameworks SubTopic: AppKit
Replies
Boosts
Views
Activity
6d
Reply to CATiledLayer flashes and re-draws entirely when re-drawing a single tile
I have not yet checked if the "redraws entire contents instead of specified rect" issue is still occurring. However, the "flashes on redraw" issue is still occurring with CATiledLayer in Xcode 26.6. The flash occurs even when returning 0 from CATiledLayer.fadeDuration(). It seems that each sublayer/tile of the CATiledLayer simply releases/erases its already-drawn contents before drawing the new contents. It would be nice to have the option to replace the existing drawing without erasing it first. This solution from @mgalijot: [quote='786127021, mgalijot, /thread/786127, /profile/mgalijot'] I have, however, found one interesting thing which seems to work so far: before calling setNeedsDisplayInRect (or just setNeedsDisplay, as they behave the same for CATiledLayer in my testing), cache the current layer's contents, and after calling setNeedsDisplay (or setNeedsDisplayInRect), restore the contents back to the layer. This prevents flashing and preserves any tiles that were drawn at the time of the re-draw. let c = tiledLayer.contents tiledLayer.setNeedsDisplay(tileRect) tiledLayer.contents = c [/quote] does fix the flash. Could an Apple engineer comment whether or not this is a valid workaround? Here's the relevant code I'm currently using (Swift 6): CATiledLayer subclass nonisolated final class NoFade_CATiledLayer: CATiledLayer { override class func fadeDuration() -> CFTimeInterval { 0 } } UIView layerClass override class var layerClass: AnyClass { NoFade_CATiledLayer.self } UIView draw(_:) /* This method must be marked "nonisolated" when it is called by "CATiledLayer" or one of its sublayers. Otherwise, the app crashes. */ nonisolated override func draw(_ rect: CGRect) { guard let cgContext = UIGraphicsGetCurrentContext() else { return } let cgPaths = cgPaths_Mutex.withLock { $0 } let fillColor = CGColor( srgbRed: 0.5, green: 0.5, blue: 0.5, alpha: 1 ) for cgPath in cgPaths { cgContext.addPath(cgPath) cgContext.setFillColor(fillColor) cgContext.fillPath() } } Calling setNeedsDisplay() private func onChange_cgPaths(newPaths: [CGPath]) { cgPaths_Mutex.withLock { (cgPaths: inout [CGPath]) -> Void in cgPaths = newPaths } setNeedsDisplay() }
Topic: UI Frameworks SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jul ’26
Reply to SwiftData document-based app crashes on undo/redo without ModelContext.transaction(block:)
The issue is still occurring with Xcode 26.4.1 (17E202) and macOS Tahoe 26.4.1 (25E253). I also noticed that, rarely, the following errors get logged when the app crashes instead of the error in my original post: SwiftData.DefaultStore save failed with error: Error Domain=NSCocoaErrorDomain Code=1570 "%{PROPERTY}@ is a required value." UserInfo={NSValidationErrorObject=<NSManagedObject: 0x9da1b20d0> (entity: ChildItem; id: 0x9d7f324a0 <x-coredata:///ChildItem/tA0242788-AD81-4A4A-82BD-92796386C7E75>; data: { index = nil; parentItem = "0x9d7f32380 <x-coredata:///ParentItem/tA0242788-AD81-4A4A-82BD-92796386C7E73>"; }), NSLocalizedDescription=%{PROPERTY}@ is a required value., NSValidationErrorKey=index, NSValidationErrorValue=null} SwiftData/ModelContext.swift:3256: Fatal error: Illegal attempt to resolve a fault against a store that is not known to this model context: PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(backing: SwiftData.PersistentIdentifier.PersistentIdentifierBacking.managedObjectID(0x9d7f32380 <x-coredata:///ParentItem/tA0242788-AD81-4A4A-82BD-92796386C7E73>))) SwiftData.ModelContext Can't show source file for stack frame 8: ParentItem.childItems.getter The file path does not exist on the file system: /var/folders/sb/kvhs_53d49n1djmvf6jbf6lh0000gp/T/swift-generated-sources/@__swiftmacro_12DocumentTest10ParentItemC10childItems18_PersistedPropertyfMa_.swift However, I don't know how to reproduce these specific errors. They get logged randomly and rarely. Most of the time, the error in my original post gets logged.
Topic: App & System Services SubTopic: iCloud Tags:
Replies
Boosts
Views
Activity
Apr ’26