fix: prevent UI freeze when loading large remote hosts files#242
Open
fix: prevent UI freeze when loading large remote hosts files#242
Conversation
Large remote hosts files (e.g. StevenBlack/hosts ~1MB, ~77K domains) caused the app to become unresponsive due to synchronous syntax highlighting processing the entire document on the main thread. - Refactor HostsTextView to highlight large documents (>50KB) in async chunks of ~100KB, yielding to the run loop between chunks. A generation counter cancels stale passes on file switch or user edit. - Replace eager .draggable(hosts.contents()) with lazy .onDrag using NSItemProvider so sidebar rendering no longer reads file contents. - Dispatch all HostsDownloader delegate callbacks to the main thread to fix data races from NSURLSession background queue callbacks. - Add O(1) NSString.length check before O(n) string comparison in HostsTextViewRepresentable.updateNSView.
Add replaceContentWith: method that bypasses the expensive synchronous textStorageDidProcessEditing: callback during bulk text replacement. This avoids the O(n) lineRangeForRange: computation that blocked the main thread on every file switch. Highlighting is instead triggered manually after replacement — async for large files, batched sync for small files.
Add tests proving text view layer is fast: - Small file switching: ~5ms per switch - replaceContentWith: no regression vs direct assignment - No notification cascade during selection changes - No HostsNodeNeedsUpdate posted during selection
The updateNSView guard was comparing the full text content (O(n)) on every @published property change, not just selection changes. For a 16K-line file, each comparison took ~22ms, causing visible lag when multiple re-renders occurred per click. Fix: decouple HostsTextViewRepresentable from the monolithic store and use a two-tier guard: - O(1) pointer check for selection changes (always replace) - Token-based check for external content updates (compare only when rowRefreshToken changes) - Skip entirely when neither selection nor token changed Also adds integration tests for the full HostsDataStore → updateNSView pipeline, objectWillChange publication counting, and pointer-based guard verification.
…cking When switching to a large hosts file (>50K chars), replaceContentWith: called highlightAsyncFrom:0 synchronously, blocking the main thread for ~20ms on a 1.38MB file. Dispatch the first chunk via dispatch_async like subsequent chunks, reducing switch time to ~1.5ms.
Three targeted fixes for UI lockup when switching between local files while a large remote file (e.g. StevenBlack ~1MB) is configured: - Coalesce rowRefreshToken updates in HostsDataStore so 9-12 rapid notifications from a download lifecycle produce 1 SwiftUI re-render instead of 9-12 - Remove duplicate HostsFileSavedNotification in RemoteHostsManager (hostsController saveHosts: already posts it) - Make dscacheutil -flushcache non-blocking using terminationHandler instead of [task waitUntilExit] (~9ms saved per call)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
HostsTextViewto highlight large documents (>50KB) asynchronously in ~100KB chunks, yielding to the run loop between each chunk.draggable(hosts.contents())inSidebarViewwith lazy.onDragusingNSItemProviderso sidebar rendering no longer reads full file contentsHostsDownloaderdelegate callbacks to the main thread to fix data races fromNSURLSessionbackground queueNSString.lengthcomparison before O(n) string equality check inHostsTextViewRepresentable.updateNSViewTest plan
https://raw.githubusercontent.com/StevenBlack/hosts/master/hostsas a remote hosts file — UI should remain responsive