Open
Conversation
Move NSFileManager trashItemAtURL: calls to a background queue and switch shuffle-related CoreData saves from synchronous (performBlockAndWait:) to asynchronous (performBlock:), eliminating multiple sources of main thread blocking during the trash operation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
Problem
When using Cog with a large playlist and trashing songs via "Move to Trash" the UI freezes noticeably, anywhere from a few hundred milliseconds to several seconds depending on playlist size and whether App Sandbox is enabled. This makes the workflow of listening through a playlist and trashing unwanted songs feel sluggish.
Root Cause
The
trashObjectsAtArrangedObjectIndexes:method inPlaylistController.mwas doing all of its work synchronously on the main thread:NSFileManager trashItemAtURL:— the actual file move to Trash, which is especially slow under App Sandbox due to security framework coordinationcommitPersistentStore— a synchronous CoreData save (performBlockAndWait:) after removing entries from the playlistresetShuffleList→addShuffledListToFront, each containing their own synchronouscommitPersistentStorecallsWith shuffle enabled, a single trash operation could trigger 3 synchronous CoreData saves plus the file I/O, all blocking the UI.
Changes
trashItemAtURL:calls are dispatched viadispatch_async. File URLs and CoreDataobjectIDs are captured on the main thread first (sincePlaylistEntryis a managed object), then the file operations run in the background. After completion,trashUrlis updated on the CoreData context queue viaperformBlock:.commitPersistentStoreAsync— a new method usingperformBlock:(non-blocking) instead ofperformBlockAndWait:(blocking).addShuffledListToFront,addShuffledListToBack, andresetShuffleListnow usecommitPersistentStoreAsync. These methods only persist shuffle indexes, which are regenerated on app launch anyway, so there's no durability concern.Benchmarks
Measured on a playlist with ~2000 entries, trashing 1 entry at a time (Debug build, shuffle enabled):
Before (all synchronous on main thread)
After (file trash + CoreData saves async)
These improvements scale further with larger playlists and under App Sandbox, where the file trash and CoreData save costs are significantly higher.
I'm not sure what your policy is regarding clanker PRs but I used Claude to identify and fix the issue after experiencing it myself. Let me know if what needs to be changed and I will revise my PR. :)