From 2e86bede0305c9b4954b15d1153f32a9ba6f3753 Mon Sep 17 00:00:00 2001 From: mszhangopopop <128134674+mszhangopopop@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:00:48 +0800 Subject: [PATCH 1/2] Move sheet presentation to SelectorSheetModifier Refactor sheet presentation logic into SelectorSheetModifier. --- TrollFools/AppListView.swift | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/TrollFools/AppListView.swift b/TrollFools/AppListView.swift index 5ad5aff5..c0383c09 100644 --- a/TrollFools/AppListView.swift +++ b/TrollFools/AppListView.swift @@ -99,11 +99,10 @@ struct AppListView: View { var content: some View { styledNavigationView .animation(.easeOut, value: appList.activeScopeApps.keys) - .sheet(item: $selectorOpenedURL) { urlWrapper in - AppListView() - .environmentObject(AppListModel(selectorURL: urlWrapper.url)) - } + .modifier(SelectorSheetModifier(isSelectorMode: appList.isSelectorMode, selectorOpenedURL: $selectorOpenedURL)) .onOpenURL { url in + guard !appList.isSelectorMode else { return } + let ext = url.pathExtension.lowercased() guard url.isFileURL, ext == "dylib" || ext == "deb" || ext == "zip" @@ -120,7 +119,14 @@ struct AppListView: View { } } - selectorOpenedURL = urlIdent + if selectorOpenedURL != nil { + selectorOpenedURL = nil + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + selectorOpenedURL = urlIdent + } + } else { + selectorOpenedURL = urlIdent + } } .onAppear { if Double.random(in: 0 ..< 1) < 0.1 { @@ -508,6 +514,22 @@ struct AppListView: View { } } +struct SelectorSheetModifier: ViewModifier { + let isSelectorMode: Bool + @Binding var selectorOpenedURL: URLIdentifiable? + + func body(content: Content) -> some View { + if isSelectorMode { + content + } else { + content.sheet(item: $selectorOpenedURL) { urlWrapper in + AppListView() + .environmentObject(AppListModel(selectorURL: urlWrapper.url)) + } + } + } +} + struct URLIdentifiable: Identifiable { let url: URL var id: String { url.absoluteString } From 03b8705021d7c4cc57f792629d554898ac61db14 Mon Sep 17 00:00:00 2001 From: mszhangopopop <128134674+mszhangopopop@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:09:42 +0800 Subject: [PATCH 2/2] CFNotificationCenter observer memory leak Memory Leak in AppListModel: > Changed Unmanaged.passRetained(self) to Unmanaged.passUnretained(self) to prevent background zombie instances and fix the memory leak. --- TrollFools/AppListModel.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/TrollFools/AppListModel.swift b/TrollFools/AppListModel.swift index 572b9de2..c6381ba8 100644 --- a/TrollFools/AppListModel.swift +++ b/TrollFools/AppListModel.swift @@ -92,11 +92,10 @@ final class AppListModel: ObservableObject { .store(in: &cancellables) let darwinCenter = CFNotificationCenterGetDarwinNotifyCenter() - CFNotificationCenterAddObserver(darwinCenter, Unmanaged.passRetained(self).toOpaque(), { _, observer, _, _, _ in - guard let observer = Unmanaged.fromOpaque(observer!).takeUnretainedValue() as AppListModel? else { - return - } - observer.applicationChanged.send() + CFNotificationCenterAddObserver(darwinCenter, Unmanaged.passUnretained(self).toOpaque(), { _, observer, _, _, _ in + guard let observerPtr = observer else { return } + let observerObj = Unmanaged.fromOpaque(observerPtr).takeUnretainedValue() + observerObj.applicationChanged.send() }, "com.apple.LaunchServices.ApplicationsChanged" as CFString, nil, .coalesce) }