Fix numerous concurrency warnings.

This commit is contained in:
Brent Simmons 2024-04-07 22:15:35 -07:00
parent 52345724ce
commit dfcf567270
13 changed files with 111 additions and 79 deletions

View File

@ -271,7 +271,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
}
}
private func importOPML(for account: Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
private func importOPML(for account: Account, opmlFile: URL, completion: @escaping @Sendable (Result<Void, Error>) -> Void) {
let data: Data
do {
@ -286,6 +286,8 @@ final class FeedlyAccountDelegate: AccountDelegate {
refreshProgress.addToNumberOfTasksAndRemaining(1)
caller.importOpml(data) { result in
MainActor.assumeIsolated {
switch result {
case .success:
os_log(.debug, log: self.log, "Import OPML done.")
@ -305,6 +307,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
}
}
}
}
func createFolder(for account: Account, name: String) async throws -> Folder {

View File

@ -8,7 +8,7 @@
import Articles
import Database
@preconcurrency import Parser
import Parser
import Web
import SyncDatabase
import os.log

View File

@ -9,7 +9,8 @@
import Foundation
public protocol ContainerIdentifiable {
var containerID: ContainerIdentifier? { get }
@MainActor var containerID: ContainerIdentifier? { get }
}
public enum ContainerIdentifier: Hashable, Equatable, Sendable {

View File

@ -14,7 +14,7 @@ import Feedly
protocol FeedlyAPICallerDelegate: AnyObject {
/// Implemented by the `FeedlyAccountDelegate` reauthorize the client with a fresh OAuth token so the client can retry the unauthorized request.
/// Pass `true` to the completion handler if the failing request should be retried with a fresh token or `false` if the unauthorized request should complete with the original failure error.
func reauthorizeFeedlyAPICaller(_ caller: FeedlyAPICaller, completionHandler: @escaping (Bool) -> ())
@MainActor func reauthorizeFeedlyAPICaller(_ caller: FeedlyAPICaller, completionHandler: @escaping (Bool) -> ())
}
final class FeedlyAPICaller {
@ -86,9 +86,10 @@ final class FeedlyAPICaller {
isSuspended = false
}
func send<R: Decodable>(request: URLRequest, resultType: R.Type, dateDecoding: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecoding: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys, completion: @escaping (Result<(HTTPURLResponse, R?), Error>) -> Void) {
func send<R: Decodable & Sendable>(request: URLRequest, resultType: R.Type, dateDecoding: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecoding: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys, completion: @escaping (Result<(HTTPURLResponse, R?), Error>) -> Void) {
transport.send(request: request, resultType: resultType, dateDecoding: dateDecoding, keyDecoding: keyDecoding) { [weak self] result in
assert(Thread.isMainThread)
MainActor.assumeIsolated {
switch result {
case .success:
@ -133,8 +134,9 @@ final class FeedlyAPICaller {
}
}
}
}
func importOpml(_ opmlData: Data, completion: @escaping (Result<Void, Error>) -> ()) {
func importOpml(_ opmlData: Data, completion: @escaping @Sendable (Result<Void, Error>) -> ()) {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))
@ -566,7 +568,7 @@ extension FeedlyAPICaller: OAuthAcessTokenRefreshRequesting {
extension FeedlyAPICaller: FeedlyGetCollectionsService {
func getCollections(completion: @escaping (Result<[FeedlyCollection], Error>) -> ()) {
func getCollections(completion: @escaping @Sendable (Result<[FeedlyCollection], Error>) -> ()) {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))

View File

@ -43,5 +43,5 @@ public protocol OAuthAcessTokenRefreshRequesting {
/// Implemented by concrete types to perform the actual request.
protocol OAuthAccessTokenRefreshing: AnyObject {
func refreshAccessToken(with refreshToken: String, client: OAuthAuthorizationClient, completion: @escaping (Result<OAuthAuthorizationGrant, Error>) -> ())
@MainActor func refreshAccessToken(with refreshToken: String, client: OAuthAuthorizationClient, completion: @escaping (Result<OAuthAuthorizationGrant, Error>) -> ())
}

View File

@ -28,6 +28,7 @@ public enum CloudKitZoneError: LocalizedError {
}
public protocol CloudKitZoneDelegate: AnyObject {
func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result<Void, Error>) -> Void);
}

View File

@ -31,6 +31,8 @@ public final class FeedlyGetCollectionsOperation: FeedlyOperation, FeedlyCollect
os_log(.debug, log: log, "Requesting collections.")
service.getCollections { result in
MainActor.assumeIsolated {
switch result {
case .success(let collections):
os_log(.debug, log: self.log, "Received collections: %{public}@", collections.map { $0.id })
@ -43,4 +45,5 @@ public final class FeedlyGetCollectionsOperation: FeedlyOperation, FeedlyCollect
}
}
}
}
}

View File

@ -9,5 +9,5 @@
import Foundation
public protocol FeedlyGetCollectionsService: AnyObject {
func getCollections(completion: @escaping (Result<[FeedlyCollection], Error>) -> ())
func getCollections(completion: @escaping @Sendable (Result<[FeedlyCollection], Error>) -> ())
}

View File

@ -10,7 +10,7 @@ import Cocoa
import os.log
import UniformTypeIdentifiers
class ShareViewController: NSViewController {
final class ShareViewController: NSViewController {
@IBOutlet weak var nameTextField: NSTextField!
@IBOutlet weak var folderPopUpButton: NSPopUpButton!

View File

@ -0,0 +1,10 @@
//
// File.swift
//
//
// Created by Brent Simmons on 4/7/24.
//
import Foundation
extension ParserData: @unchecked Sendable {}

View File

@ -0,0 +1,10 @@
//
// File.swift
//
//
// Created by Brent Simmons on 4/7/24.
//
import Foundation
extension RSHTMLMetadataParser: @unchecked Sendable {}

View File

@ -14,7 +14,7 @@ struct HTMLMetadataDownloader {
static let serialDispatchQueue = DispatchQueue(label: "HTMLMetadataDownloader")
@MainActor static func downloadMetadata(for url: String, _ completion: @escaping (RSHTMLMetadata?) -> Void) {
@MainActor static func downloadMetadata(for url: String, _ completion: @escaping @Sendable (RSHTMLMetadata?) -> Void) {
guard let actualURL = URL(unicodeString: url) else {
completion(nil)
return
@ -32,7 +32,7 @@ struct HTMLMetadataDownloader {
}
}
private static func parseMetadata(with parserData: ParserData, _ completion: @escaping (RSHTMLMetadata?) -> Void) {
private static func parseMetadata(with parserData: ParserData, _ completion: @escaping @Sendable (RSHTMLMetadata?) -> Void) {
serialDispatchQueue.async {
let htmlMetadata = RSHTMLMetadataParser.htmlMetadata(with: parserData)
DispatchQueue.main.async {

View File

@ -216,6 +216,7 @@ private extension FeedIconDownloader {
HTMLMetadataDownloader.downloadMetadata(for: homePageURL) { (metadata) in
MainActor.assumeIsolated {
self.urlsInProgress.remove(homePageURL)
guard let metadata = metadata else {
return
@ -223,6 +224,7 @@ private extension FeedIconDownloader {
self.pullIconURL(from: metadata, homePageURL: homePageURL, feed: feed)
}
}
}
func pullIconURL(from metadata: RSHTMLMetadata, homePageURL: String, feed: Feed) {