Fix concurrency warnings in Parser module.
This commit is contained in:
parent
f449a443d8
commit
e03ad03e60
@ -101,36 +101,37 @@ extension LocalAccountRefresher: DownloadSessionDelegate {
|
||||
}
|
||||
|
||||
let parserData = ParserData(url: feed.url, data: data)
|
||||
FeedParser.parse(parserData) { (parsedFeed, error) in
|
||||
|
||||
guard let account = feed.account, let parsedFeed = parsedFeed, error == nil else {
|
||||
completion()
|
||||
self.delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||
return
|
||||
}
|
||||
|
||||
Task { @MainActor in
|
||||
Task { @MainActor in
|
||||
|
||||
do {
|
||||
let articleChanges = try await account.update(feed: feed, with: parsedFeed)
|
||||
do {
|
||||
let parsedFeed = try await FeedParser.parse(parserData)
|
||||
|
||||
if let httpResponse = response as? HTTPURLResponse {
|
||||
feed.conditionalGetInfo = HTTPConditionalGetInfo(urlResponse: httpResponse)
|
||||
}
|
||||
feed.contentHash = dataHash
|
||||
|
||||
self.delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||
self.delegate?.localAccountRefresher(self, articleChanges: articleChanges) {
|
||||
completion()
|
||||
}
|
||||
|
||||
} catch {
|
||||
guard let account = feed.account, let parsedFeed else {
|
||||
completion()
|
||||
self.delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let articleChanges = try await account.update(feed: feed, with: parsedFeed)
|
||||
|
||||
if let httpResponse = response as? HTTPURLResponse {
|
||||
feed.conditionalGetInfo = HTTPConditionalGetInfo(urlResponse: httpResponse)
|
||||
}
|
||||
feed.contentHash = dataHash
|
||||
|
||||
self.delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||
self.delegate?.localAccountRefresher(self, articleChanges: articleChanges) {
|
||||
completion()
|
||||
}
|
||||
|
||||
} catch {
|
||||
completion()
|
||||
self.delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, shouldContinueAfterReceivingData data: Data, representedObject: AnyObject) -> Bool {
|
||||
let feed = representedObject as! Feed
|
||||
|
@ -23,14 +23,25 @@ public struct InitialFeedDownloader {
|
||||
|
||||
@MainActor public static func download(_ url: URL,_ completion: @escaping @Sendable (_ parsedFeed: ParsedFeed?) -> Void) {
|
||||
|
||||
downloadUsingCache(url) { (data, response, error) in
|
||||
guard let data = data else {
|
||||
Task {
|
||||
|
||||
guard let downloadData = try? await downloadUsingCache(url) else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
guard let data = downloadData.data else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
|
||||
let parserData = ParserData(url: url.absoluteString, data: data)
|
||||
FeedParser.parse(parserData) { (parsedFeed, error) in
|
||||
|
||||
Task.detached {
|
||||
guard let parsedFeed = try? await FeedParser.parse(parserData) else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
|
||||
completion(parsedFeed)
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
__attribute__((swift_attr("@Sendable")))
|
||||
@interface ParserData : NSObject
|
||||
|
||||
@property (nonatomic, readonly) NSString *url;
|
||||
|
@ -12,12 +12,8 @@ import ParserObjC
|
||||
// FeedParser handles RSS, Atom, JSON Feed, and RSS-in-JSON.
|
||||
// You don’t need to know the type of feed.
|
||||
|
||||
public typealias FeedParserCallback = (_ parsedFeed: ParsedFeed?, _ error: Error?) -> Void
|
||||
|
||||
public struct FeedParser {
|
||||
|
||||
private static let parseQueue = DispatchQueue(label: "FeedParser parse queue")
|
||||
|
||||
public static func canParse(_ parserData: ParserData) -> Bool {
|
||||
|
||||
let type = feedType(parserData)
|
||||
@ -30,62 +26,26 @@ public struct FeedParser {
|
||||
}
|
||||
}
|
||||
|
||||
public static func mightBeAbleToParseBasedOnPartialData(_ parserData: ParserData) -> Bool {
|
||||
public static func parse(_ parserData: ParserData) async throws -> ParsedFeed? {
|
||||
|
||||
let type = feedType(parserData, isPartialData: true)
|
||||
let type = feedType(parserData)
|
||||
|
||||
switch type {
|
||||
case .jsonFeed, .rssInJSON, .rss, .atom, .unknown:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse(_ parserData: ParserData) throws -> ParsedFeed? {
|
||||
case .jsonFeed:
|
||||
return try JSONFeedParser.parse(parserData)
|
||||
|
||||
// This is generally fast enough to call on the main thread —
|
||||
// but it’s probably a good idea to use a background queue if
|
||||
// you might be doing a lot of parsing. (Such as in a feed reader.)
|
||||
case .rssInJSON:
|
||||
return try RSSInJSONParser.parse(parserData)
|
||||
|
||||
do {
|
||||
let type = feedType(parserData)
|
||||
case .rss:
|
||||
return RSSParser.parse(parserData)
|
||||
|
||||
switch type {
|
||||
case .atom:
|
||||
return AtomParser.parse(parserData)
|
||||
|
||||
case .jsonFeed:
|
||||
return try JSONFeedParser.parse(parserData)
|
||||
|
||||
case .rssInJSON:
|
||||
return try RSSInJSONParser.parse(parserData)
|
||||
|
||||
case .rss:
|
||||
return RSSParser.parse(parserData)
|
||||
|
||||
case .atom:
|
||||
return AtomParser.parse(parserData)
|
||||
|
||||
case .unknown, .notAFeed:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
catch { throw error }
|
||||
}
|
||||
|
||||
public static func parse(_ parserData: ParserData, _ completion: @escaping FeedParserCallback) {
|
||||
|
||||
parseQueue.async {
|
||||
do {
|
||||
let parsedFeed = try parse(parserData)
|
||||
DispatchQueue.main.async {
|
||||
completion(parsedFeed, nil)
|
||||
}
|
||||
}
|
||||
catch {
|
||||
DispatchQueue.main.async {
|
||||
completion(nil, error)
|
||||
}
|
||||
}
|
||||
case .unknown, .notAFeed:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user