fix: concurrency code for RSSTools

This commit is contained in:
Duong Thai 2024-03-15 10:41:43 +07:00
parent ff452338dc
commit 1439e29d64
2 changed files with 31 additions and 11 deletions

View file

@ -191,7 +191,7 @@ enum RSSTools {
} }
@MainActor @MainActor
static func load(feedURL: URL) async -> RSSFeed? { static func load(feedURL: URL) async -> Void? {
let sendableFeed = await Task.detached { let sendableFeed = await Task.detached {
await RSSTools.getFeedData(from: feedURL) await RSSTools.getFeedData(from: feedURL)
}.value }.value
@ -203,15 +203,31 @@ enum RSSTools {
await sendableFeed.getSendableItemData() await sendableFeed.getSendableItemData()
}.value }.value
return await backgroundContext.perform { let rssFeed = RSSFeed(context: backgroundContext, sendableData: sendableFeed)
let rssFeed = RSSFeed(context: backgroundContext, sendableData: sendableFeed)
let rssItems = sendableItems.compactMap { let rssItems = sendableItems.compactMap {
RSSItem(context: backgroundContext, sendableData: $0) RSSItem(context: backgroundContext, sendableData: $0)
}
rssFeed.items = NSSet(array: rssItems)
return rssFeed
} }
for item in rssItems { item.feed = rssFeed }
return try? backgroundContext.save()
}
@MainActor
static func fetchFeed(url: URL) async -> RSSFeed? {
let request: NSFetchRequest<RSSFeed> = {
let request = RSSFeed.fetchRequest()
request.fetchLimit = 1
request.predicate = NSPredicate(format: "%K = %@",
#keyPath(RSSFeed.feedURL),
url as CVarArg)
request.relationshipKeyPathsForPrefetching = ["items"]
return request
}()
let context = RSSDataController.shared.viewContext
guard let feed = (try? context.fetch(request))?.first else { return nil }
return feed
} }
@MainActor @MainActor

View file

@ -66,10 +66,14 @@ public struct RSSAddNewFeed: View {
feed?.managedObjectContext?.rollback() feed?.managedObjectContext?.rollback()
downloadingTask = Task { downloadingTask = Task {
let rssFeed = await RSSTools.load(feedURL: url) guard let _ = await RSSTools.load(feedURL: url),
let rssFeed = await RSSTools.fetchFeed(url: url)
else {
self.state = .noData(url: url)
return
}
if Task.isCancelled { return } if Task.isCancelled { return }
if let rssFeed { self.state = .downloaded(feed: rssFeed, url: url) } self.state = .downloaded(feed: rssFeed, url: url)
else { self.state = .noData(url: url) }
} }
case .downloaded(let feed, _): case .downloaded(let feed, _):
self.feed = feed self.feed = feed