Concurrency

RSS for tag

Concurrency is the notion of multiple things happening at the same time.

Posts under Concurrency tag

102 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Fix actor-isolated class is different from nonisolated subclass error
I'm trying to migrate my fairly large application to Swift Concurrency. I've have a class marked as @MainActor that sub-classes a 3rd party abstract class that is not migrated to Swift Concurrency. I get the following error: Main actor-isolated class 'MyClass' has different actor isolation from nonisolated superclass 'OtherAbstractClass'; this is an error in the Swift 6 language mode My class needs to be MainActor as it uses other code that is required to be on the MainActor. I can't see how to suppress this warning, I know as a guarantee that the abstract class will always be on the main thread so I need a way of telling the compiler that when I don't own the 3rd party code. import OtherAbstractModule @MainActor class MyClass: OtherAbstractClass { .... } How can I satisfy the compiler in this case?
1
0
361
4w
Using Core Data with the Swift 6 language mode
I'm starting to work on updating my code for Swift 6. I have a number of pieces of code that look like this: private func updateModel() async throws { try await context.perform { [weak self] in // do some work } } After turning on strict concurrency checking, I get warnings on blocks like that saying "Sending 'self.context' risks causing data races; this is an error in the Swift 6 language mode." What's the best way for me to update this Core Data code to work with Swift 6?
4
1
437
2w
SwiftData SchemaMigrationPlan and VersionedSchema not Sendable?
I've just tried to update a project that uses SwiftData to Swift 6 using Xcode 16 beta 1, and it's not working due to missing Sendable conformance on a couple of types (MigrationStage and Schema.Version): struct LocationsMigrationPlan: SchemaMigrationPlan { static let schemas: [VersionedSchema.Type] = [LocationsVersionedSchema.self] static let stages: [MigrationStage] = [] } struct LocationsVersionedSchema: VersionedSchema { static let models: [any PersistentModel.Type] = [ Location.self ] static let versionIdentifier = Schema.Version(1, 0, 0) } This code results in the following errors: error: static property 'stages' is not concurrency-safe because non-'Sendable' type '[MigrationStage]' may have shared mutable state static let stages: [MigrationStage] = [] ^ error: static property 'versionIdentifier' is not concurrency-safe because non-'Sendable' type 'Schema.Version' may have shared mutable state static let versionIdentifier = Schema.Version(1, 0, 0) ^ Am I missing something, or is this a bug in the current seed? I've filed this as FB13862584.
1
2
292
4w
UIDevice: Main actor-isolated class property 'current' can not be referenced from a non-isolated context
I have a Safari Web Extension for visionOS that reads from UIDevice.current.systemVersion in order to provide the OS version number back to the JavaScript context utilizing beginRequest(with:). When switching my project to use Swift 6, I received this obscure error: Main actor-isolated class property 'current' can not be referenced from a non-isolated context Class property declared here (UIKit.UIDevice) Add '@MainActor' to make instance method 'beginRequest(with:)' part of global actor 'MainActor' Adding @MainActor causes another issue (Main actor-isolated instance method 'beginRequest(with:)' cannot be used to satisfy nonisolated protocol requirement) which suggests adding @preconcurrency to NSExtensionRequestHandling which then breaks at Non-sendable type 'NSExtensionContext' in parameter of the protocol requirement satisfied by main actor-isolated instance method 'beginRequest(with:)' cannot cross actor boundary. What's the proper solution here? Here's a simplified snippet of my code: class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { func beginRequest(with context: NSExtensionContext) { // ... var systemVersionNumber = "" systemVersionNumber = UIDevice.current.systemVersion // ... } }
1
0
307
4w
SwiftUI Shape concurrency warnings
How are SwiftUI Shapes supposed to work with Swift 6? Shape conforms to View which uses @MainActor but the path function and animatableData are both nonisolated. How can they access animatable properties that have to be a var on the main actor? Below is a simple Shape that will show these warnings: struct SimpleShape: Shape { var width: Double var animatableData: Double { get { width } set { width = newValue } } func path(in rect: CGRect) -> Path { var path = Path() let width = self.width path.addRect(.init(origin: rect.origin, size: .init(width: width, height: rect.height))) return path } }
5
1
390
4w
Crash objc_retain_x0
Attaching several crash traces: 2024-02-29_22-48-33.6864_-0600-3f948243e21b4c68d77a38d9cf1cecfdfe2c1565.crash 2024-03-04_15-00-02.9335_-0600-75000cd5acd63ba1434f2ffb3648b97259dddb88.crash 2024-03-05_08-55-47.2097_-0500-f682b25663107ad46f091d65f402f2be31f3f3c6.crash 2024-03-11_08-09-00.4057_-0400-e37d1a635d51afbb67ac38b42dd79c1718a408e8.crash 2024-03-15_16-20-22.6446_-0600-d4ebccf455e8305038ca564a39a5661a1dce6231.crash The final code: - (NSObject*)objectAtIndex:(NSUInteger)index { if (index < self.count) { return [self.embeddedArray objectAtIndex:index]; } else { [PNDErrorReporting reportError:PNDErrorReasonTypeSafeCollectionCrashPrevented message:@"Error msg"]; return nil; } } We subclass NSMutableArray to prevent potential crashes. but we encounter a new crash in our sdk for one of the clients. Also we noticed the stack trace skipped one of the frames (stack calls) in the crash report, in which cases the stack trace wont be identical to the actual code (beside inline)?
8
0
270
3w
Function called isolated on MainActor via an isolated parameter are not considered run on the MainActor
If I try to compile the following, I get a compilation error: import Foundation func isolatedPrint<A : Actor>(on actor: isolated A) { print("hello") } Task{ @MainActor in isolatedPrint(on: MainActor.shared) } The error: toto.swift:9:2: error: expression is 'async' but is not marked with 'await' isolatedPrint(on: MainActor.shared) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ await toto.swift:9:2: note: calls to global function 'isolatedPrint(on:)' from outside of its actor context are implicitly asynchronous isolatedPrint(on: MainActor.shared) ^ I don’t understand why the compiler does not detect the function is called on the MainActor via the actor parameter.
1
0
276
Jun ’24
Ensuring exclusive access to a function in structured concurrency
So our back end manages tokens in a strange way. Whenever we try to request a new access token using our refresh token, it invalidates our old refresh token and returns us with a new access + refresh token. The problem with this is that multiple concurrent network requests can see that a user's access token has expired and try to get a new access token, potentially causing us to get a 401 unauthorized error. Is there any way with structured/unstructured concurrency to ensure that our method for grabbing the access token can only at max be run once at a time? Im assuming the only realistic way would be to do something like this: @MyGlobalActor private var tokenTask: Task<String, any Error>? @MyGlobalActor func getAccessToken() async await -> String { if let tokenTask { return try await tokenTask.value } self.tokenTask = Task<String, any Error> { // refresh access token } let token = try await self.tokenTask!.value self.tokenTask = nil return token }
1
0
241
Jun ’24
WKScriptMessageHandlerWithReply and strict concurrency checking
Hi, I'm trying to implement a type conforming to WKScriptMessageHandlerWithReply while having Swift's strict concurrency checking enabled. It's not been fun. The protocol contains the following method (there's also one with a callback, but we're in 2024): func userContentController( controller: WKUserContentController, didReceive message: WKScriptMessage ) async -> (Any?, String?) WKScriptMessage's properties like body must be accessed on the main thread. But since WKScriptMessageHandlerWithReply is not @MainActor, neither can this method be so marked (same for the conforming type). At the same time WKScriptMessage is not Sendable, so I can't handle it in Task { @MainActor in this method, because that leads to Capture of 'message' with non-sendable type 'WKScriptMessage' in a `@Sendable` closure That leaves me with @preconcurrency import - is that the way to go? Should I file a feedback for this or is it somehow working as intended?
3
0
312
May ’24
[SwiftUI][Crash] Weird crash with FocusBrigde.hasHostingController.getter
This is a bug I have been trying to identify and fix for more than 3 weeks. This bug mostly happens in production. The stack trace doesn't help that much, because it looks like the app is crashing due to some SwiftUI internal methods. I tried everything in my power to debug and find this bug, still nothing. Due to the lack of 100% reproducibility, it made me think that this bug is either memory-pressure related or Swift concurrency related. When does it happen: This bug happens when presenting a SwiftUI modal (UIViewControllerRepresentable)[A] which in terms presents a UIHostingController modal[B] which then presents a modally a SwiftUI sheet [C] The bug happens somewhere around staying in [C] or after dismissing it. Context: The app lifecycle is SwiftUI. The main SwiftUI screen in the app body is a UIViewControllerRepresentable containing a UISplitViewController. Here is a screenshot from the crash log in Xcode. Anyone facing a similar issue?
2
0
356
May ’24
Apple MusicKit
Hello. I have the following question. I call the nextBatch() method on MusicItemCollection to get the next collection of artist albums. Here is my method: func allAlbums2(artist: Artist) async throws -> [Album] { var allAlbums: [Album] = [] artist.albums?.forEach { allAlbums.append($0) } guard let albums = artist.albums else { return [] } var albumsCollection = albums while albumsCollection.hasNextBatch { let response = try await albumsCollection.nextBatch() if let response { albumsCollection = response var albums = [Album]() albumsCollection.forEach({ albums.append($0)}) allAlbums.append(contentsOf: albums) } } return allAlbums } The problem is as follows. Sometimes it happens that some albums not in nextBatch are not returned (I noticed one, I didn't check the others). This happens once every 50-100 requests. The number of batches is returned the same when the album is skipped. The same albums are returned in the batch where the album was missed. I have a question, do I have a problem with multi-threading or something else or is it a problem in the API. The file contains prints of the returned batches. One with a missing album, the other without a missing one. There are about 3000 lines in the file. I will be grateful for a hint or an answer. Thank you! Here link to file: https://files.fm/u/nj4r5wgyg3
0
0
296
Apr ’24
Using SwiftData: Model not saved when inserting from background actor
Hi everyone, I'm trying to make use of a background actor in my SwiftUI project. Inserting data works with the ModelContainer's mainContext. Another context in a ModelActor, however, fails to write into the same database. I verify the results by opening the SQLite file on the file system. While the mainContext.insert call does indeed insert a row into the table, the ModelActor's context fails to do so. There is no error or message received in the ModelActor. The property autosaveEnabled is set to true. I wrote a sample project to reproduce the issue in isolation. It consists of a single source file that introduces the Model ToDo, the ToDoView, initializes the ModelContainer and ModelActor. Please find the source code below. Is there any mistake in my approach? import SwiftUI import SwiftData @Model final class ToDo { let title: String init(title: String) { self.title = title } } @main struct testSwiftDataApp: App { @State var modelContainer: ModelContainer @State var backgroundData: BackgroundDataActor init() { let modelContainer: ModelContainer = try! ModelContainer(for: ToDo.self) self.modelContainer = modelContainer self.backgroundData = BackgroundDataActor( modelContainer: modelContainer ) } var body: some Scene { WindowGroup { ToDoView(backgroundData: self.backgroundData) .modelContainer(modelContainer) } } } struct ToDoView: View { @Environment(\.modelContext) var modelContext @Query var todos: [ToDo] let backgroundData: BackgroundDataActor var modelContainer: ModelContainer { self.modelContext.container } var body: some View { VStack { Text("Add ToDo") TextField( "", text: .constant( "URL to database: " + "\(self.modelContainer.configurations.first!.url)" ) ) // This action will be invoked on the ModelActor's context Button { Task { let todo = ToDo(title: "Step 1") await self.backgroundData.store( id: todo.persistentModelID ) } } label: { Text("Create ToDo in background") } // This action will be invoked on the mainContext Button { Task { let todo = ToDo(title: "Step 2") self.modelContainer.mainContext.insert(todo) } } label: { Text("Create ToDo in foreground") } // Show the query results VStack { Text("Available ToDos") ForEach(self.todos) { Text($0.title) } } } } } @ModelActor actor BackgroundDataActor: ModelActor { func store(id: PersistentIdentifier) { print("Trying to save") print("Is auto save enabled: \(self.modelContext.autosaveEnabled)") if let dbo = self[id, as: ToDo.self] { self.modelContext.insert(dbo) try! self.modelContext.save() print("Saved into database") } } }
1
0
350
Apr ’24
Ambiguous "#locationUpdater received unhandled message" error from CLLocationUpdate.liveUpdates()
I’m working on updating one of my apps to the asynchronous location updates API, but have been running into an unhelpful error. Here's my code: @Observable class CurrentLocation: NSObject, CLLocationManagerDelegate { private(set) var location: CLLocation? private let locationManager = CLLocationManager() override init() { super.init() self.locationManager.delegate = self self.locationManager.desiredAccuracy = kCLLocationAccuracyReduced } func requestLocation() async throws { print("requesting location") requestAccess() for try await update in CLLocationUpdate.liveUpdates() { self.location = update.location if update.isStationary { break } } } } But after calling requestLocation(), I receive the following error in the console without any location updates: {"msg":"#locationUpdater received unhandled message", "Message":kCLConnectionMessageCompensatedLocation, "self":"0x600002eaa600"} Googling this error yields absolutely no matches. I’ve ensured that I have the necessary Info.plist entries (as the old, synchronous location update code I have is also working without issues). I’d be grateful for any assistance!
0
0
307
Apr ’24
Non-sendable type ModelContext on MainActor
Hi, just trying to learn how to work with mainActor. I am in a need of analyzing users data with API service one a background. Whenever user saves a post into SwiftData, I need to analyze that posts asynchronously. Here is my current code, which by the way works, but I am getting warning here; actor DatabaseInteractor { let networkInteractor: any NetworkInteractor = NetworkInteractorImpl() func loadUserProfile() async -&gt; String { do { let objects = try await modelContainer.mainContext.fetch(FetchDescriptor&lt;ProfileSwiftData&gt;()) if let profileTest = objects.first?.profile { return profileTest } } catch { } return "" } I get a warning on let objects line. Warning: Non-sendable type 'ModelContext' in implicitly asynchronous access to main actor-isolated property 'mainContext' cannot cross actor boundary
1
0
632
Apr ’24
What is the difference between OSAllocatedUnfairLock's withLock and withLockUnchecked functions?
OSAllocatedUnfairLock has two different methods for executing a block of code with the lock held: withLock() and withLockUnchecked(). The only difference between the two is that the former has the closure and return type marked as Sendable. withLockUnchecked() has a comment (that is for reasons I do not understand not visible in the documentation) saying: /// This method does not enforce sendability requirement /// on closure body and its return type. /// The caller of this method is responsible for ensuring references /// to non-sendables from closure uphold the Sendability contract. What I do not understand here is why Sendable conformance would be needed. These function should call this block synchronously in the same context, and return the return value through a normal function return. None of this should require the types to be Sendable. This seems to be supported by this paragraph of the documentation for OSAllocatedUnfairLock: /// This lock must be unlocked from the same thread that locked it. As such, it /// is unsafe to use `lock()` / `unlock()` across an `await` suspension point. /// Instead, use `withLock` to enforce that the lock is only held within /// a synchronous scope. So, why does this Sendable requirement exist, and in practice, if I did want to use withLockUnchecked, how would I "uphold the Sendability contract"? To summarise the question in a more concise way: Is there an example where using withLockUnchecked() would actually cause a problem, and using withLock() instead would catch that problem?
7
0
539
Apr ’24