{"id":42856,"date":"2024-04-15T16:00:55","date_gmt":"2024-04-15T20:00:55","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=42856"},"modified":"2024-12-10T11:48:41","modified_gmt":"2024-12-10T16:48:41","slug":"nstableview-with-swiftui","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2024\/04\/15\/nstableview-with-swiftui\/","title":{"rendered":"NSTableView With SwiftUI"},"content":{"rendered":"<p><a href=\"https:\/\/byla.lt\/posts\/in-search-of-smooth-scroll\/\">Edvinas Byla<\/a> (via <a href=\"https:\/\/iosdevweekly.com\/issues\/655?#start\">Dave Verwer<\/a>):<\/p>\n<blockquote cite=\"https:\/\/byla.lt\/posts\/in-search-of-smooth-scroll\/\"><p>The [<code>LazyVGrid<\/code>] user experience isn&rsquo;t great, but it&rsquo;s still probably okayish for a version 1.0.0 release. The performance issues are less noticeable with fewer items unless you&rsquo;re used to high-quality apps. But then there was this one thing that bugged me: the behavior of the context menu.<\/p><p>On macOS, right-clicking an item usually selects it and shows the context menu. SwiftUI&rsquo;s <code>.contextMenu<\/code> shows the menu but doesn&rsquo;t select or give you any callback for selecting the item. This can be confusing because you don&rsquo;t know if you&rsquo;re seeing the menu for the right item.<\/p><\/blockquote>\n<p>You&rsquo;re <em>supposed<\/em> to be able to use the contextual menu to interact with a list item <em>without<\/em> changing the selection.<\/p>\n\n<blockquote cite=\"https:\/\/byla.lt\/posts\/in-search-of-smooth-scroll\/\"><p>Damn, did [<code>NSTableView<\/code>] feel buttery.<\/p>\n<p>[&#8230;]<\/p>\n<p>But the main reason for this overhaul wasn&rsquo;t just the scroll performance. It was also fixing that annoying context menu issue.<\/p>\n<p>[&#8230;]<\/p>\n<p>On top of all this, I managed to get rid of some extra code for keyboard navigation, clean up the layout mess, and now I can easily adjust and rearrange columns.<\/p>\n<p>[&#8230;]<\/p>\n<p>The remaining part of this post will go over some challenges and gotchas of replacing <code>LazyVGrid<\/code> with <code>NSTableView<\/code> while still reusing SwiftUI views.<\/p><\/blockquote>\n\n<p>Lots of good stuff there about using SwiftUI views inside the column headers and table cells.<\/p>\n\n<blockquote cite=\"https:\/\/byla.lt\/posts\/in-search-of-smooth-scroll\/\"><p>I don&rsquo;t want the takeaway to be that SwiftUI is slow and AppKit is fast, or that SwiftUI on macOS isn&rsquo;t ready for serious apps. In reality, the very complex template editor for this app is almost entirely written in SwiftUI, which handles it impressively well.<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.social\/@helge\/112243117036053924\">Helge He&szlig;<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@helge\/112243117036053924\"><p>SwiftUI is part of the future, it is not &ldquo;the&rdquo; future. It is still unclear how sth basic like a text editor can work with the scalability constraints of SwiftUI. Or a List w\/ more than 1k items.\nEverything becomes easier if you start to acknowledge that SwiftUI is a convenience extension to Cocoa, not a replacement in any way. And miraculously SwiftUI also allows super easy integration w\/ Cocoa, making sure it is no either or &#x1F642;<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.social\/@malhal\/112245978983832422\">Malcolm Hall<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@malhal\/112245978983832422\"><p>having a constant number of <code>View<\/code>s per row (i.e. no <code>if<\/code>s) is one of the performance secrets recently explained at 16:25 <a href=\"https:\/\/developer.apple.com\/wwdc23\/10160?time=985\">here<\/a>.<\/p><p>Another is no sorting\/filtering in body, e.g. it could be bounced through <code>onChange<\/code> and saved in another state<\/p><\/blockquote>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/03\/11\/mac-dialog-in-auto-layout-vs-swiftui\/\">Mac Dialog in Auto Layout vs. SwiftUI<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/02\/13\/dragging-from-a-list-with-swiftui\/\">Dragging From a List With SwiftUI<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2023\/08\/11\/appkit-vs-swiftui-stable-vs-shiny\/\">AppKit vs. SwiftUI: Stable vs. Shiny<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2022\/11\/30\/swiftui-performance-gotchas\/\">SwiftUI Performance Gotchas<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2022\/05\/24\/swiftui-in-2022\/\">SwiftUI in 2022<\/a><\/li>\n<\/ul>\n\n<p id=\"nstableview-with-swiftui-update-2024-04-26\">Update (2024-04-26): <a href=\"https:\/\/mastodon.social\/@agiletortoise\/112292725300391336\">Greg Pierce<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@agiletortoise\/112292725300391336\">\n<p>SwiftUI Q: Is there a trick to get lazy generation of a context menu on a list row?<\/p>\n<\/blockquote>\n\n<p id=\"nstableview-with-swiftui-update-2024-12-10\">Update (2024-12-10): <a href=\"https:\/\/mastodon.social\/@stefanpauwels\/113605101510226100\">Stefan Pauwels<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@stefanpauwels\/113605101510226100\">\n<p>SwiftUI <code>Table<\/code> has <a href=\"http:\/\/www.openradar.me\/FB13639482\">serious performance<\/a> <a href=\"https:\/\/stackoverflow.com\/questions\/74412194\/can-you-disable-content-diffing-to-improve-performance\">issues on macOS<\/a>, where it should be at its most useful! :-(<\/p>\n<\/blockquote>","protected":false},"excerpt":{"rendered":"<p>Edvinas Byla (via Dave Verwer): The [LazyVGrid] user experience isn&rsquo;t great, but it&rsquo;s still probably okayish for a version 1.0.0 release. The performance issues are less noticeable with fewer items unless you&rsquo;re used to high-quality apps. But then there was this one thing that bugged me: the behavior of the context menu.On macOS, right-clicking an [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2024-04-15T20:00:58Z","apple_news_api_id":"235205bd-a145-4a05-a29f-e3e72f16d25c","apple_news_api_modified_at":"2024-12-10T16:48:32Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAQ==","apple_news_api_share_url":"https:\/\/apple.news\/AI1IFvaFFSgWin-PnLxbSXA","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[69,30,2385,138,71,1812],"class_list":["post-42856","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-cocoa","tag-mac","tag-macos-14-sonoma","tag-optimization","tag-programming","tag-swiftui"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/42856","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=42856"}],"version-history":[{"count":4,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/42856\/revisions"}],"predecessor-version":[{"id":46113,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/42856\/revisions\/46113"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=42856"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=42856"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=42856"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}