mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2024-12-22 23:58:36 +01:00
Fix numerous concurrency warnings.
This commit is contained in:
parent
5bf5a067ab
commit
fb0479f324
@ -74,7 +74,9 @@ final class CloudKitAccountDelegate: AccountDelegate {
|
||||
op.completionBlock = { mainThreadOperaion in
|
||||
completion()
|
||||
}
|
||||
mainThreadOperationQueue.add(op)
|
||||
Task { @MainActor in
|
||||
mainThreadOperationQueue.add(op)
|
||||
}
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
@ -124,7 +126,9 @@ final class CloudKitAccountDelegate: AccountDelegate {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
mainThreadOperationQueue.add(op)
|
||||
Task { @MainActor in
|
||||
mainThreadOperationQueue.add(op)
|
||||
}
|
||||
}
|
||||
|
||||
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
@ -777,7 +781,9 @@ private extension CloudKitAccountDelegate {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
mainThreadOperationQueue.add(op)
|
||||
Task { @MainActor in
|
||||
mainThreadOperationQueue.add(op)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,7 +108,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
completion()
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
@MainActor func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
assert(Thread.isMainThread)
|
||||
|
||||
guard currentSyncAllOperation == nil else {
|
||||
@ -145,7 +145,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
operationQueue.add(syncAllOperation)
|
||||
}
|
||||
|
||||
func syncArticleStatus(for account: Account, completion: ((Result<Void, Error>) -> Void)? = nil) {
|
||||
@MainActor func syncArticleStatus(for account: Account, completion: ((Result<Void, Error>) -> Void)? = nil) {
|
||||
sendArticleStatus(for: account) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
@ -163,7 +163,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
@MainActor func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
// Ensure remote articles have the same status as they do locally.
|
||||
let send = FeedlySendArticleStatusesOperation(database: database, service: caller, log: log)
|
||||
send.completionBlock = { operation in
|
||||
@ -181,7 +181,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
///
|
||||
/// - Parameter account: The account whose articles have a remote status.
|
||||
/// - Parameter completion: Call on the main queue.
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
@MainActor func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
guard let credentials = credentials else {
|
||||
return completion(.success(()))
|
||||
}
|
||||
@ -314,8 +314,8 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
|
||||
@MainActor func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
|
||||
do {
|
||||
guard let credentials = credentials else {
|
||||
throw FeedlyAccountDelegateError.notLoggedIn
|
||||
@ -374,8 +374,8 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
feed.editedName = name
|
||||
}
|
||||
|
||||
func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
@MainActor func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
do {
|
||||
guard let credentials = credentials else {
|
||||
throw FeedlyAccountDelegateError.notLoggedIn
|
||||
@ -425,7 +425,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
folder.removeFeed(feed)
|
||||
}
|
||||
|
||||
func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
@MainActor func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let from = from as? Folder, let to = to as? Folder else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(FeedlyAccountDelegateError.addFeedChooseFolder))
|
||||
@ -458,7 +458,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
to.addFeed(feed)
|
||||
}
|
||||
|
||||
func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
@MainActor func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
if let existingFeed = account.existingFeed(withURL: feed.url) {
|
||||
account.addFeed(existingFeed, to: container) { result in
|
||||
switch result {
|
||||
@ -480,7 +480,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func restoreFolder(for account: Account, folder: Folder, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
@MainActor func restoreFolder(for account: Account, folder: Folder, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
let group = DispatchGroup()
|
||||
|
||||
for feed in folder.topLevelFeeds {
|
||||
@ -516,10 +516,12 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
|
||||
self.database.insertStatuses(syncStatuses) { _ in
|
||||
self.database.selectPendingCount { result in
|
||||
if let count = try? result.get(), count > 100 {
|
||||
self.sendArticleStatus(for: account) { _ in }
|
||||
MainActor.assumeIsolated {
|
||||
if let count = try? result.get(), count > 100 {
|
||||
self.sendArticleStatus(for: account) { _ in }
|
||||
}
|
||||
completion(.success(()))
|
||||
}
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
@ -533,7 +535,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
credentials = try? account.retrieveCredentials(type: .oauthAccessToken)
|
||||
}
|
||||
|
||||
func accountWillBeDeleted(_ account: Account) {
|
||||
@MainActor func accountWillBeDeleted(_ account: Account) {
|
||||
let logout = FeedlyLogoutOperation(account: account, service: caller, log: log)
|
||||
// Dispatch on the shared queue because the lifetime of the account delegate is uncertain.
|
||||
MainThreadOperationQueue.shared.add(logout)
|
||||
@ -598,6 +600,8 @@ extension FeedlyAccountDelegate: FeedlyAPICallerDelegate {
|
||||
completionHandler(refreshAccessTokenDelegate.didReauthorize && !operation.isCanceled)
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(refreshAccessToken)
|
||||
Task { @MainActor in
|
||||
MainThreadOperationQueue.shared.add(refreshAccessToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate,
|
||||
private let operationQueue = MainThreadOperationQueue()
|
||||
var addCompletionHandler: ((Result<Void, Error>) -> ())?
|
||||
|
||||
init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, log: OSLog, customFeedName: String? = nil) throws {
|
||||
@MainActor init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, log: OSLog, customFeedName: String? = nil) throws {
|
||||
|
||||
let validator = FeedlyFeedContainerValidator(container: container)
|
||||
let (folder, collectionId) = try validator.getValidContainer()
|
||||
|
@ -30,8 +30,8 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
|
||||
private var feedResourceId: FeedlyFeedResourceId?
|
||||
var addCompletionHandler: ((Result<Feed, Error>) -> ())?
|
||||
|
||||
init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIdsService: FeedlyGetStreamIdsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress, log: OSLog) throws {
|
||||
|
||||
@MainActor init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIdsService: FeedlyGetStreamIdsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress, log: OSLog) throws {
|
||||
|
||||
|
||||
let validator = FeedlyFeedContainerValidator(container: container)
|
||||
(self.folder, self.collectionId) = try validator.getValidContainer()
|
||||
@ -75,7 +75,7 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
|
||||
super.didFinish(with: error)
|
||||
}
|
||||
|
||||
func feedlySearchOperation(_ operation: FeedlySearchOperation, didGet response: FeedlyFeedsSearchResponse) {
|
||||
@MainActor func feedlySearchOperation(_ operation: FeedlySearchOperation, didGet response: FeedlyFeedsSearchResponse) {
|
||||
guard !isCanceled else {
|
||||
return
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation {
|
||||
private let operationQueue = MainThreadOperationQueue()
|
||||
private let finishOperation: FeedlyCheckpointOperation
|
||||
|
||||
init(account: Account, missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService, log: OSLog) {
|
||||
@MainActor init(account: Account, missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService, log: OSLog) {
|
||||
self.account = account
|
||||
self.operationQueue.suspend()
|
||||
self.missingArticleEntryIdProvider = missingArticleEntryIdProvider
|
||||
@ -43,27 +43,29 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation {
|
||||
let feedlyAPILimitBatchSize = 1000
|
||||
for articleIds in Array(articleIds).chunked(into: feedlyAPILimitBatchSize) {
|
||||
|
||||
let provider = FeedlyEntryIdentifierProvider(entryIds: Set(articleIds))
|
||||
let getEntries = FeedlyGetEntriesOperation(account: account, service: getEntriesService, provider: provider, log: log)
|
||||
getEntries.delegate = self
|
||||
self.operationQueue.add(getEntries)
|
||||
|
||||
let organiseByFeed = FeedlyOrganiseParsedItemsByFeedOperation(account: account,
|
||||
parsedItemProvider: getEntries,
|
||||
log: log)
|
||||
organiseByFeed.delegate = self
|
||||
organiseByFeed.addDependency(getEntries)
|
||||
self.operationQueue.add(organiseByFeed)
|
||||
|
||||
let updateAccount = FeedlyUpdateAccountFeedsWithItemsOperation(account: account,
|
||||
organisedItemsProvider: organiseByFeed,
|
||||
log: log)
|
||||
|
||||
updateAccount.delegate = self
|
||||
updateAccount.addDependency(organiseByFeed)
|
||||
self.operationQueue.add(updateAccount)
|
||||
Task { @MainActor in
|
||||
let provider = FeedlyEntryIdentifierProvider(entryIds: Set(articleIds))
|
||||
let getEntries = FeedlyGetEntriesOperation(account: account, service: getEntriesService, provider: provider, log: log)
|
||||
getEntries.delegate = self
|
||||
self.operationQueue.add(getEntries)
|
||||
|
||||
finishOperation.addDependency(updateAccount)
|
||||
let organiseByFeed = FeedlyOrganiseParsedItemsByFeedOperation(account: account,
|
||||
parsedItemProvider: getEntries,
|
||||
log: log)
|
||||
organiseByFeed.delegate = self
|
||||
organiseByFeed.addDependency(getEntries)
|
||||
self.operationQueue.add(organiseByFeed)
|
||||
|
||||
let updateAccount = FeedlyUpdateAccountFeedsWithItemsOperation(account: account,
|
||||
organisedItemsProvider: organiseByFeed,
|
||||
log: log)
|
||||
|
||||
updateAccount.delegate = self
|
||||
updateAccount.addDependency(organiseByFeed)
|
||||
self.operationQueue.add(updateAccount)
|
||||
|
||||
finishOperation.addDependency(updateAccount)
|
||||
}
|
||||
}
|
||||
|
||||
operationQueue.resume()
|
||||
|
@ -34,7 +34,7 @@ final class FeedlySyncAllOperation: FeedlyOperation {
|
||||
///
|
||||
/// Download articles for statuses at the union of those statuses without its corresponding article and those included in 3 (changed since last successful sync).
|
||||
///
|
||||
init(account: Account, feedlyUserId: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIdsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIdsService, getStreamIdsService: FeedlyGetStreamIdsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress, log: OSLog) {
|
||||
@MainActor init(account: Account, feedlyUserId: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIdsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIdsService, getStreamIdsService: FeedlyGetStreamIdsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress, log: OSLog) {
|
||||
self.syncUUID = UUID()
|
||||
self.log = log
|
||||
self.operationQueue.suspend()
|
||||
@ -126,7 +126,7 @@ final class FeedlySyncAllOperation: FeedlyOperation {
|
||||
self.operationQueue.add(finishOperation)
|
||||
}
|
||||
|
||||
convenience init(account: Account, feedlyUserId: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress, log: OSLog) {
|
||||
@MainActor convenience init(account: Account, feedlyUserId: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress, log: OSLog) {
|
||||
self.init(account: account, feedlyUserId: feedlyUserId, lastSuccessfulFetchStartDate: lastSuccessfulFetchStartDate, markArticlesService: caller, getUnreadService: caller, getCollectionsService: caller, getStreamContentsService: caller, getStarredService: caller, getStreamIdsService: caller, getEntriesService: caller, database: database, downloadProgress: downloadProgress, log: log)
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
|
||||
private let log: OSLog
|
||||
private let finishOperation: FeedlyCheckpointOperation
|
||||
|
||||
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?, log: OSLog) {
|
||||
@MainActor init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?, log: OSLog) {
|
||||
self.account = account
|
||||
self.resource = resource
|
||||
self.service = service
|
||||
@ -41,7 +41,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
|
||||
enqueueOperations(for: nil)
|
||||
}
|
||||
|
||||
convenience init(account: Account, credentials: Credentials, service: FeedlyGetStreamContentsService, newerThan: Date?, log: OSLog) {
|
||||
@MainActor convenience init(account: Account, credentials: Credentials, service: FeedlyGetStreamContentsService, newerThan: Date?, log: OSLog) {
|
||||
let all = FeedlyCategoryResourceId.Global.all(for: credentials.username)
|
||||
self.init(account: account, resource: all, service: service, isPagingEnabled: true, newerThan: newerThan, log: log)
|
||||
}
|
||||
@ -56,7 +56,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
|
||||
super.didCancel()
|
||||
}
|
||||
|
||||
func enqueueOperations(for continuation: String?) {
|
||||
@MainActor func enqueueOperations(for continuation: String?) {
|
||||
os_log(.debug, log: log, "Requesting page for %{public}@", resource.id)
|
||||
let operations = pageOperations(for: continuation)
|
||||
operationQueue.addOperations(operations)
|
||||
@ -89,7 +89,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
|
||||
return [getPage, organiseByFeed, updateAccount]
|
||||
}
|
||||
|
||||
func feedlyGetStreamContentsOperation(_ operation: FeedlyGetStreamContentsOperation, didGetContentsOf stream: FeedlyStream) {
|
||||
@MainActor func feedlyGetStreamContentsOperation(_ operation: FeedlyGetStreamContentsOperation, didGetContentsOf stream: FeedlyStream) {
|
||||
guard !isCanceled else {
|
||||
os_log(.debug, log: log, "Cancelled requesting page for %{public}@", resource.id)
|
||||
return
|
||||
|
@ -10,7 +10,7 @@
|
||||
import Foundation
|
||||
import CloudKit
|
||||
|
||||
public class CloudKitError: LocalizedError {
|
||||
public final class CloudKitError: LocalizedError {
|
||||
|
||||
public let error: Error
|
||||
|
||||
|
@ -27,13 +27,13 @@ public enum CloudKitZoneError: LocalizedError {
|
||||
}
|
||||
}
|
||||
|
||||
public protocol CloudKitZoneDelegate: class {
|
||||
public protocol CloudKitZoneDelegate: AnyObject {
|
||||
func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result<Void, Error>) -> Void);
|
||||
}
|
||||
|
||||
public typealias CloudKitRecordKey = (recordType: CKRecord.RecordType, recordID: CKRecord.ID)
|
||||
|
||||
public protocol CloudKitZone: class {
|
||||
public protocol CloudKitZone: AnyObject {
|
||||
|
||||
static var qualityOfService: QualityOfService { get }
|
||||
|
||||
|
@ -15,7 +15,7 @@ import Foundation
|
||||
/// When it’s canceled, it should do its best to stop
|
||||
/// doing whatever it’s doing. However, it should not
|
||||
/// leave data in an inconsistent state.
|
||||
public protocol MainThreadOperation: class {
|
||||
public protocol MainThreadOperation: AnyObject {
|
||||
|
||||
// These three properties are set by MainThreadOperationQueue. Don’t set them.
|
||||
var isCanceled: Bool { get set } // Check this at appropriate times in case the operation has been canceled.
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol MainThreadOperationDelegate: class {
|
||||
public protocol MainThreadOperationDelegate: AnyObject {
|
||||
func operationDidComplete(_ operation: MainThreadOperation)
|
||||
func cancelOperation(_ operation: MainThreadOperation)
|
||||
func make(_ childOperation: MainThreadOperation, dependOn parentOperation: MainThreadOperation)
|
||||
@ -26,14 +26,14 @@ public protocol MainThreadOperationDelegate: class {
|
||||
public final class MainThreadOperationQueue {
|
||||
|
||||
/// Use the shared queue when you don’t need to create a separate queue.
|
||||
public static let shared: MainThreadOperationQueue = {
|
||||
@MainActor public static let shared: MainThreadOperationQueue = {
|
||||
MainThreadOperationQueue()
|
||||
}()
|
||||
|
||||
private var operations = [Int: MainThreadOperation]()
|
||||
private var pendingOperationIDs = [Int]()
|
||||
private var currentOperationID: Int?
|
||||
private static var incrementingID = 0
|
||||
@MainActor private static var incrementingID = 0
|
||||
private var isSuspended = false
|
||||
private let dependencies = MainThreadOperationDependencies()
|
||||
|
||||
@ -51,7 +51,7 @@ public final class MainThreadOperationQueue {
|
||||
}
|
||||
|
||||
/// Add an operation to the queue.
|
||||
public func add(_ operation: MainThreadOperation) {
|
||||
@MainActor public func add(_ operation: MainThreadOperation) {
|
||||
precondition(Thread.isMainThread)
|
||||
operation.operationDelegate = self
|
||||
let operationID = ensureOperationID(operation)
|
||||
@ -67,12 +67,12 @@ public final class MainThreadOperationQueue {
|
||||
|
||||
/// Add multiple operations to the queue.
|
||||
/// This has the same effect as calling addOperation one-by-one.
|
||||
public func addOperations(_ operations: [MainThreadOperation]) {
|
||||
@MainActor public func addOperations(_ operations: [MainThreadOperation]) {
|
||||
operations.forEach{ add($0) }
|
||||
}
|
||||
|
||||
/// Add a dependency. Do this *before* calling addOperation, since addOperation might run the operation right away.
|
||||
public func make(_ childOperation: MainThreadOperation, dependOn parentOperation: MainThreadOperation) {
|
||||
@MainActor public func make(_ childOperation: MainThreadOperation, dependOn parentOperation: MainThreadOperation) {
|
||||
precondition(Thread.isMainThread)
|
||||
let childOperationID = ensureOperationID(childOperation)
|
||||
let parentOperationID = ensureOperationID(parentOperation)
|
||||
@ -91,7 +91,7 @@ public final class MainThreadOperationQueue {
|
||||
|
||||
/// Cancel some operations. If any of them have dependent operations,
|
||||
/// those operations will be canceled also.
|
||||
public func cancelOperations(_ operations: [MainThreadOperation]) {
|
||||
@MainActor public func cancelOperations(_ operations: [MainThreadOperation]) {
|
||||
precondition(Thread.isMainThread)
|
||||
let operationIDsToCancel = operations.map{ ensureOperationID($0) }
|
||||
assert(allOperationIDsArePendingOrCurrent(operationIDsToCancel))
|
||||
@ -106,7 +106,7 @@ public final class MainThreadOperationQueue {
|
||||
///
|
||||
/// This will cancel the current operation, not just pending operations,
|
||||
/// if it has the specified name.
|
||||
public func cancelOperations(named name: String) {
|
||||
@MainActor public func cancelOperations(named name: String) {
|
||||
precondition(Thread.isMainThread)
|
||||
guard let operationsToCancel = pendingAndCurrentOperations(named: name) else {
|
||||
return
|
||||
@ -137,7 +137,7 @@ extension MainThreadOperationQueue: MainThreadOperationDelegate {
|
||||
operationDidFinish(operation)
|
||||
}
|
||||
|
||||
public func cancelOperation(_ operation: MainThreadOperation) {
|
||||
@MainActor public func cancelOperation(_ operation: MainThreadOperation) {
|
||||
cancelOperations([operation])
|
||||
}
|
||||
}
|
||||
@ -227,13 +227,13 @@ private extension MainThreadOperationQueue {
|
||||
return !operation.isCanceled && !dependencies.operationIDIsBlockedByDependency(operation.id!)
|
||||
}
|
||||
|
||||
func createOperationID() -> Int {
|
||||
@MainActor func createOperationID() -> Int {
|
||||
precondition(Thread.isMainThread)
|
||||
Self.incrementingID += 1
|
||||
return Self.incrementingID
|
||||
}
|
||||
|
||||
func ensureOperationID(_ operation: MainThreadOperation) -> Int {
|
||||
@MainActor func ensureOperationID(_ operation: MainThreadOperation) -> Int {
|
||||
if let operationID = operation.id {
|
||||
return operationID
|
||||
}
|
||||
|
@ -8,19 +8,19 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol UndoableCommand: class {
|
||||
public protocol UndoableCommand: AnyObject {
|
||||
|
||||
var undoActionName: String { get }
|
||||
var redoActionName: String { get }
|
||||
var undoManager: UndoManager { get }
|
||||
@MainActor var undoActionName: String { get }
|
||||
@MainActor var redoActionName: String { get }
|
||||
@MainActor var undoManager: UndoManager { get }
|
||||
|
||||
func perform() // must call registerUndo()
|
||||
func undo() // must call registerRedo()
|
||||
@MainActor func perform() // must call registerUndo()
|
||||
@MainActor func undo() // must call registerRedo()
|
||||
}
|
||||
|
||||
extension UndoableCommand {
|
||||
|
||||
public func registerUndo() {
|
||||
@MainActor public func registerUndo() {
|
||||
|
||||
undoManager.setActionName(undoActionName)
|
||||
undoManager.registerUndo(withTarget: self) { (target) in
|
||||
@ -28,7 +28,7 @@ extension UndoableCommand {
|
||||
}
|
||||
}
|
||||
|
||||
public func registerRedo() {
|
||||
@MainActor public func registerRedo() {
|
||||
|
||||
undoManager.setActionName(redoActionName)
|
||||
undoManager.registerUndo(withTarget: self) { (target) in
|
||||
@ -39,30 +39,30 @@ extension UndoableCommand {
|
||||
|
||||
// Useful for view controllers.
|
||||
|
||||
public protocol UndoableCommandRunner: class {
|
||||
public protocol UndoableCommandRunner: AnyObject {
|
||||
|
||||
var undoableCommands: [UndoableCommand] { get set }
|
||||
var undoManager: UndoManager? { get }
|
||||
|
||||
func runCommand(_ undoableCommand: UndoableCommand)
|
||||
func clearUndoableCommands()
|
||||
@MainActor var undoableCommands: [UndoableCommand] { get set }
|
||||
@MainActor var undoManager: UndoManager? { get }
|
||||
|
||||
@MainActor func runCommand(_ undoableCommand: UndoableCommand)
|
||||
@MainActor func clearUndoableCommands()
|
||||
}
|
||||
|
||||
public extension UndoableCommandRunner {
|
||||
|
||||
func runCommand(_ undoableCommand: UndoableCommand) {
|
||||
|
||||
@MainActor func runCommand(_ undoableCommand: UndoableCommand) {
|
||||
|
||||
pushUndoableCommand(undoableCommand)
|
||||
undoableCommand.perform()
|
||||
}
|
||||
|
||||
func pushUndoableCommand(_ undoableCommand: UndoableCommand) {
|
||||
|
||||
@MainActor func pushUndoableCommand(_ undoableCommand: UndoableCommand) {
|
||||
|
||||
undoableCommands += [undoableCommand]
|
||||
}
|
||||
|
||||
func clearUndoableCommands() {
|
||||
|
||||
@MainActor func clearUndoableCommands() {
|
||||
|
||||
// Useful, for example, when timeline is reloaded and the list of articles changes.
|
||||
// Otherwise things like Redo Mark Read are ambiguous.
|
||||
// (Do they apply to the previous articles or to the current articles?)
|
||||
|
Loading…
Reference in New Issue
Block a user