fix: Prevent UICollectionView crash from concurrent bookmark list updates

Add isUpdating flag to prevent race conditions when updating the bookmark list.
This fixes crashes that occurred when returning to the app after adding a bookmark
via the share extension while the list was being updated.
This commit is contained in:
Ilyas Hallak 2025-10-19 20:40:02 +02:00
parent 6906509aea
commit d97e404cc7

View File

@ -22,9 +22,12 @@ class BookmarksViewModel {
var showingAddBookmarkFromShare = false var showingAddBookmarkFromShare = false
var shareURL = "" var shareURL = ""
var shareTitle = "" var shareTitle = ""
// Undo delete functionality // Undo delete functionality
var pendingDeletes: [String: PendingDelete] = [:] // bookmarkId -> PendingDelete var pendingDeletes: [String: PendingDelete] = [:] // bookmarkId -> PendingDelete
// Prevent concurrent updates
private var isUpdating = false
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
@ -104,15 +107,19 @@ class BookmarksViewModel {
@MainActor @MainActor
func loadBookmarks(state: BookmarkState = .unread, type: [BookmarkType] = [.article], tag: String? = nil) async { func loadBookmarks(state: BookmarkState = .unread, type: [BookmarkType] = [.article], tag: String? = nil) async {
guard !isUpdating else { return }
isUpdating = true
defer { isUpdating = false }
isLoading = true isLoading = true
errorMessage = nil errorMessage = nil
currentState = state currentState = state
currentType = type currentType = type
currentTag = tag currentTag = tag
offset = 0 offset = 0
hasMoreData = true hasMoreData = true
do { do {
let newBookmarks = try await getBooksmarksUseCase.execute( let newBookmarks = try await getBooksmarksUseCase.execute(
state: state, state: state,
@ -142,18 +149,20 @@ class BookmarksViewModel {
} }
// Don't clear bookmarks on error - keep existing data visible // Don't clear bookmarks on error - keep existing data visible
} }
isLoading = false isLoading = false
isInitialLoading = false isInitialLoading = false
} }
@MainActor @MainActor
func loadMoreBookmarks() async { func loadMoreBookmarks() async {
guard !isLoading && hasMoreData else { return } // prevent multiple loads guard !isLoading && hasMoreData && !isUpdating else { return } // prevent multiple loads
isUpdating = true
defer { isUpdating = false }
isLoading = true isLoading = true
errorMessage = nil errorMessage = nil
do { do {
offset += limit // inc. offset offset += limit // inc. offset
let newBookmarks = try await getBooksmarksUseCase.execute( let newBookmarks = try await getBooksmarksUseCase.execute(
@ -181,7 +190,7 @@ class BookmarksViewModel {
errorMessage = "Error loading more bookmarks" errorMessage = "Error loading more bookmarks"
} }
} }
isLoading = false isLoading = false
} }