Concurrency

RSS for tag

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

Posts under Concurrency tag

68 Posts

Post

Replies

Boosts

Views

Activity

Structured concurrency + preconcurrency API (SFAuthorizationPluginView)
I'm having trouble dealing with concurrency with the SFAuthorizationPluginView. Does anybody know how this can be solved? https://developer.apple.com/documentation/securityinterface/sfauthorizationpluginview The crux of it is: If I inherit an object as part of an API, and the API is preconcurrency, and thus is nonisolated (but in reality is @MainActor), how do I return a @MainActor GUI element? https://developer.apple.com/documentation/securityinterface/sfauthorizationpluginview/firstresponder() The longer story: I made my view class inherit SFAuthorizationPluginView. The API is preconcurrency (but not marked as preconcurrency) I started using concurrency in my plugin to retrieve data over XPC. (https://developer.apple.com/documentation/xpc/xpcsession + https://developer.apple.com/documentation/swift/withcheckedthrowingcontinuation(isolation:function:_:)) Once I retrieve the data over XPC, I need to post it on GUI, hence I've set my view class as @MainActor in order to do the thread switch. Swift compiler keeps complaining: override func firstResponder() -> NSResponder? { return usernameField } "Main actor-isolated property 'usernameField' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode" override func firstResponder() -> NSResponder? { MainActor.assumeIsolated { return usernameField } } "Sending 'self' risks causing data races; this is an error in the Swift 6 language mode" I think fundamentally, the API is forcing me to give away a @MainActor variable through a nonisolated function, and there is no way to shut up the compiler. I've tried @preconcurrency and it has no effect as far as I can tell. I've also tried marking the function explicitly as nonisolated. The rest of the API are less problematic, but returning a GUI variable is exceptionally difficult.
2
0
805
Jul ’25
Playground Macro Raises Error when compiled with Swift 6
In my Xcode app, I was attempting to use the #Playground macro to play around with some of the Foundation Model features to see if they would work for my iOS app. However, every time I used a #Playground macro, even if it was empty, it would receive the following error: /var/folders/q2/x5b9x0y161bb2l_0yj1_j6wm0000gn/T/swift-generated-sources/@__swiftmacro_20PlaygroundMacroIssue0022ContentViewswift_tiAIefMX26_0_33_B691877350F20F2DFC040B9E585F4D10Ll0A0fMf_.swift:51:5 Main actor-isolated let '$s20PlaygroundMacroIssue0022ContentViewswift_tiAIefMX26_0_33_B691877350F20F2DFC040B9E585F4D10Ll0A0fMf_23PlaygroundContentRecordfMu_' can not be referenced from a nonisolated context Here are my Xcode and system versions: Mac is running the first public beta of Tahoe. iOS Simulator is running 26.0 dev beta 4. Xcode is Xcode 26 beta 4. So, I went to try to reproduce the error in a blank iOS app project (the error above is the one that I reproduced in that project). Here are the steps that I took. I created a new iOS project in Xcode 26. I went into the ContentView.swift that was created for me and imported the Playgrounds module and created a blank #Playground at the bottom of the file. I then compiled the project and it ran just fine. To try to find out what the issue was, I looked at the concurrency settings. In my real app, Strict Concurrency Checking was set to Complete but was Minimal in my test project. So I went and changed that setting in my real app and it didn't fix anything. Next, I looked at the Swift Version, which turned out to be the culprit. My test app was running Swift 5 whereas the real app was running Swift 6. It seems to have crashed while running Swift 6, not 5. I have trouble understanding what the error is saying. I have tried using the Code Intelligence feature to fix the bug but it hasn't helped. Has anyone here experienced a similar bug? Is there something I can do to fix it or is this an error in Xcode that should be reported? I have attached an iCloud link to my test project if anybody wants to see if they can reproduce the issue: here Thanks!
2
0
236
Aug ’25
Expected behavior from apps when MacOS goes to sleep
Every time macOS goes to sleep the processes get suspended which is expected. But during the sleep period, all processes keep coming back and they all get a small execution window where they make some n/w requests. Regardless of what power settings i have. It also does not matter whether my app is a daemon or not Is there any way that i can disable this so that when system is in sleep, it stays in suspended, no intermittent execution window? I have tried disabling Wake for network access setting but processes still keep getting intermittent execution window. Is there any way that i can prevent my app from coming back while in sleep. I don't want my app to get execution window, perform some executions and then get suspended not knowing when it will get execution window again?
1
0
155
Aug ’25
`.task(id:_:)` starting in the `Task.isCancelled` state
I'm running into a weird SwiftUI concurrency issue that only seems to happen on a real device (iOS 18.5 in my case), and not in simulator. I have a NavigationSplitView where the Detail view uses .task(id:_:) to perform some async work upon appearance (in my real-world case, a map snapshot). When running this on a real device, the first execution of the task works as expected. However, any task subsequent executions, even ones for the same id, always start in the Task.isCancelled state. Is there something about .task(id:_:) that I'm misunderstanding, or have I stumbled upon a serious bug here? import SwiftUI struct ContentView: View { var body: some View { TaskBugSplitView() } } struct TestItem: Identifiable, Hashable { var id: Int var name: String } struct TaskBugSplitView: View { @State private var selectedItemIndex: [TestItem].Index? @State private var testItems: [TestItem] = [ TestItem(id: 1, name: "First Item"), TestItem(id: 2, name: "Second Item"), TestItem(id: 3, name: "Third Item"), TestItem(id: 4, name: "Fourth Item"), TestItem(id: 5, name: "Fifth Item") ] var body: some View { NavigationSplitView { List(testItems.indices, id: \.self, selection: $selectedItemIndex) { item in Text(testItems[item].name) } } detail: { if let selectedItemIndex { TaskBugDetailView(item: testItems[selectedItemIndex]) } else { Text("Select an item") .foregroundStyle(.secondary) } } } } struct TaskBugDetailView: View { @State var item: TestItem @State private var taskResult = "Not started" var body: some View { VStack(spacing: 20) { Text("Item: \(item.name)") .font(.title2) Text("Task Result:") .font(.headline) Text(taskResult) .foregroundStyle(taskResult.contains("CANCELLED") ? .red : .primary) Spacer() } .padding() .navigationTitle(item.name) .task(id: item.id) { // BUG: On real devices, Task.isCancelled is true immediately for all tasks // after the first successful one, even though the ID has changed if Task.isCancelled { taskResult = "CANCELLED at start" print("Task cancelled at start for item \(item.id)") return } taskResult = "SUCCESS" print("Task completed successfully for item \(item.id)") } } }
2
0
159
Aug ’25
`awakeFromNib` and Approachable Concurrency
When attempting to compile an existing project with Swift 6, default isolation set to MainActor and approachable concurrency enabled, all awakeFromNib functions lead to the following compile error: "Main actor-isolated instance method 'awakeFromNib()' has different actor isolation from nonisolated overridden declaration" I've seen articles before approachable concurrency stating that one remedy is to wrap code within the function with MainActor.assumeIsolated{ }. However, that no longer addresses the error. One combination of changes that removes the error is doing the following: nonisolated override func awakeFromNib() { super.awakeFromNib() MainActor.assumeIsolated { ... } } Honestly, that's a mess. Long term, we are looking to remove all these functions, but does anyone have a better solution?
3
0
257
Aug ’25
TVTopShelfContentProvider and Swift 6 Concurrency
I have a TVTopShelfContentProvider that implements func loadTopShelfContent() async -> (any TVTopShelfContent)? When running on Xcode 26 b5 I am seeing the following error in swift 6 mode. Non-Sendable type '(any TVTopShelfContent)?' cannot be returned from nonisolated override to caller of superclass instance method 'loadTopShelfContent()' I'm not sure exactly what's changed here as it used to compile just fine but it's unclear now how I can work-around this error or how the API is supposed to be used. The following definition is enough to trigger the error in Swift 6 language mode. import TVServices class ContentProvider: TVTopShelfContentProvider { override func loadTopShelfContent() async -> (any TVTopShelfContent)? { return nil } } I can "fix" it by adding @preconcurrency to the TVServices import but it seems like this API is unusable currently? Or maybe it's user error on my part?
2
0
128
Aug ’25
Swift 6 conversion for IBOutlet
I'm struggling to convert Swift 5 to Swift 6. As advised in doc, I first turned strict concurrency ON. I got no error. Then, selected swift6… and problems pop up. I have a UIViewController with IBOutlets: eg a TextField. computed var eg duree func using UNNotification: func userNotificationCenter I get the following error in the declaration line of the func userNotificationCenter: Main actor-isolated instance method 'userNotificationCenter(_:didReceive:withCompletionHandler:)' cannot be used to satisfy nonisolated requirement from protocol 'UNUserNotificationCenterDelegate' So, I declared the func as non isolated. This func calls another func func2, which I had also to declare non isolated. Then I get error on the computed var used in func2 Main actor-isolated property 'duree' can not be referenced from a nonisolated context So I declared duree as nonsilated(unsafe). Now comes the tricky part. The computed var references the IBOutlet dureeField if dureeField.text == "X" leading to the error Main actor-isolated property 'dureeField' can not be referenced from a nonisolated context So I finally declared the class as mainActor and the textField as nonisolated @IBOutlet nonisolated(unsafe) weak var dureeField : UITextField! That silences the error (but declaring unsafe means I get no extra robustness with swift6) just to create a new one when calling dureeField.text: Main actor-isolated property 'text' can not be referenced from a nonisolated context Question: how to address properties inside IBOutlets ? I do not see how to declare them non isolated and having to do it on each property of each IBOutlet would be impracticable. The following did work, but will make code very verbose: if MainActor.assumeIsolated({dureeField.text == "X"}) { So I must be missing something.
5
0
789
Aug ’25
Should ModelActor be used to populate a view?
I'm working with SwiftData and SwiftUI and it's not clear to me if it is good practice to have a @ModelActor directly populate a SwiftUI view. For example when having to combine manual lab results and clinial results from HealthKit. The Clinical lab results are an async operation: @ModelActor actor LabResultsManager { func fetchLabResultsWithHealthKit() async throws -> [LabResultDto] { let manualEntries = try modelContext.fetch(FetchDescriptor<LabResult>()) let clinicalLabs = (try? await HealthKitService.getLabResults()) ?? [] return (manualEntries + clinicalLabs).sorted { $0.date > $1.date }.map { return LabResultDto(from: $0) } } } struct ContentView: View { @State private var labResults: [LabResultDto] = [] var body: some View { List(labResults, id: \.id) { result in VStack(alignment: .leading) { Text(result.testName) Text(result.date, style: .date) } } .task { do { let labManager = LabResultsManager() labResults = try await labManager.fetchLabResultsWithHealthKit() } catch { // Handle error } } } } EDIT: I have a few views that would want to use these labResults so I need an implementation that can be reused. Having to fetch and combine in each view will not be good practice. Can I pass a modelContext to a viewModel?
4
0
405
Aug ’25
SwiftData Fatal error: Editors must register their identifiers before invoking operations on this store
I have a UIKit app where I've adopted SwiftData and I'm struggling with a crash coming in from some of my users. I'm not able to reproduce it myself and as it only happens to a small fraction of my user base, it seems like a race condition of some sort. This is the assertion message: SwiftData/DefaultStore.swift:453: Fatal error: API Contract Violation: Editors must register their identifiers before invoking operations on this store SwiftData.DefaultStore: 00CF060A-291A-4E79-BEC3-E6A6B20F345E did not. (ID is unique per crash) This is the ModelActor that crashes: @available(iOS 17, *) @ModelActor actor ConsumptionDatabaseStorage: ConsumptionSessionStorage { struct Error: LocalizedError { var errorDescription: String? } private let sortDescriptor = [SortDescriptor(\SDConsumptionSession.startTimeUtc, order: .reverse)] static func createStorage(userId: String) throws -> ConsumptionDatabaseStorage { guard let appGroupContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: UserDefaults.defaultAppGroupIdentifier) else { throw Error(errorDescription: "Invalid app group container ID") } func createModelContainer(databaseUrl: URL) throws -> ModelContainer { return try ModelContainer(for: SDConsumptionSession.self, SDPriceSegment.self, configurations: ModelConfiguration(url: databaseUrl)) } let databaseUrl = appGroupContainer.appendingPathComponent("\(userId).sqlite") do { return self.init(modelContainer: try createModelContainer(databaseUrl: databaseUrl)) } catch { // Creating the model storage failed. Remove the database file and try again. try? FileManager.default.removeItem(at: databaseUrl) return self.init(modelContainer: try createModelContainer(databaseUrl: databaseUrl)) } } func isStorageEmpty() async -> Bool { (try? self.modelContext.fetchCount(FetchDescriptor<SDConsumptionSession>())) ?? 0 == 0 // <-- Crash here! } func sessionsIn(interval: DateInterval) async throws -> [ConsumptionSession] { let fetchDescriptor = FetchDescriptor(predicate: #Predicate<SDConsumptionSession> { sdSession in if let startDate = sdSession.startTimeUtc { return interval.start <= startDate && interval.end > startDate } else { return false } }, sortBy: self.sortDescriptor) let consumptionSessions = try self.modelContext.fetch(fetchDescriptor) // <-- Crash here! return consumptionSessions.map { ConsumptionSession(swiftDataSession: $0) } } func updateSessions(sessions: [ConsumptionSession]) async throws { if #unavailable(iOS 18) { // Price segments are duplicated if re-inserted so unfortunately we have to delete and reinsert sessions. // On iOS 18, this is enforced by the #Unique macro on SDPriceSegment. let sessionIds = Set(sessions.map(\.id)) try self.modelContext.delete(model: SDConsumptionSession.self, where: #Predicate<SDConsumptionSession> { sessionIds.contains($0.id) }) } for session in sessions { self.modelContext.insert(SDConsumptionSession(consumptionSession: session)) } if self.modelContext.hasChanges { try self.modelContext.save() } } func deleteAllSessions() async { if #available(iOS 18, *) { try? self.modelContainer.erase() } else { self.modelContainer.deleteAllData() } } } The actor conforms to this protocol: protocol ConsumptionSessionStorage { func isStorageEmpty() async -> Bool func hasCreditCardSessions() async -> Bool func sessionsIn(interval: DateInterval) async throws -> [ConsumptionSession] func updateSessions(sessions: [ConsumptionSession]) async throws func deleteAllSessions() async } The crash is coming in from line 30 and 41, in other words, when trying to fetch data from the database. There doesn't seem to be any common trait for the crashes. They occur across iOS versions and device types. Any idea what might cause this?
5
0
355
Aug ’25
Xcode 26: Sendable checking + NSManagedObjectContext.perform in Swift 6
I have some code which handles doing some computation on a background thread before updating Core Data NSManagedObjects by using the NSManagedObjectContext.perform functions. This code is covered in Sendable warnings in Xcode 26 (beta 6) because my NSManagedObject subclasses (autogenerated) are non-Sendable and NSManagedObjectContext.perform function takes a Sendable closure. But I can't really figure out what I should be doing. I realize this pattern is non-ideal for Swift concurrency, but it's what Core Data demands AFAIK. How do I deal with this? let moc = object.managedObjectContext! try await moc.perform { object.completed = true // Capture of 'object' with non-Sendable type 'MySpecialObject' in a '@Sendable' closure try moc.save() } Thanks in advance for your help!
1
1
187
Aug ’25
Equatable with default actor isolation of MainActor
I filed the following issue on swiftlang/swift on GitHub (Aug 8th), and a followup the swift.org forums, but not getting any replies. As we near the release of Swift 6.2, I want to know if what I'm seeing below is expected, or if it's another case where the compiler needs a fix. protocol P1: Equatable { } struct S1: P1 { } // Error: Conformance of 'S1' to protocol 'P1' crosses into main actor-isolated code an can cause data races struct S1Workaround: @MainActor P1 { } // OK // Another potential workaround if `Equatable` conformance can be moved to the conforming type. protocol P2 { } struct S2: Equatable, P2 { } // OK There was a prior compiler bug fix which addressed inhereted protocols regarding @MainActor. For Equatable, one still has to use @MainActoreven when the default actor isolation is MainActor. Also affects Hashable and any other protocol inheriting from Equatable.
3
0
1.2k
Aug ’25
Possible typo in concurrency diagram (WWDC25: Elevate an app with Swift concurrency)
Hello, While watching WWDC25: Code-along: Elevate an app with Swift concurrency at timestamp 25:48, I noticed something in the slide/diagram that might be incorrect. The diagram shows ExtractSticker twice, but based on the code context and spoken explanation, I think it was meant to be ExtractSticker and ExtractColor. Reasoning: The surrounding code and narration describe the use of async let and a Sendable Data object. From the flow, one task extracts a sticker while the other extracts a color, so it seems like the diagram is inconsistent. I do understand that with @concurrent, having two ExtractSticker operations on the same Data is technically possible (with two concurrent process executing their respective ExtractSticker) — but that would be a different meaning than what the talk was describing. Since concurrency is already a subtle and error-prone topic, I thought it was worth pointing this out. If I’m mistaken, I’d love clarification. Otherwise, this could be a small correction to keep things aligned and clearer for everyone. Minor point overall, but Swift 6’s concurrency model is doing a fantastic job at helping us write safer code—so thank you to the team for that! (Attaching screenshots for reference)
2
0
1.9k
Aug ’25
Should SwiftUI view models in Swift 6 be both @Observable and @MainActor?
Hi, In the WWDC25 session Elevate an app with Swift concurrency (timestamps: 8:04 and later), the StickerViewModel is shown annotated with @Observable but not @MainActor. The narration mentions that updates happen on the main thread, but that guarantee is left implicit in the calling code. In Swift 6, though, one of the major benefits is stronger compiler enforcement against data races and isolation rules. If a view model were also annotated with @MainActor, then the compiler could enforce that observable state is only updated on the main actor, preventing accidental background mutations or updates that can cause data races between nonisolated and main actor-isolated uses. Since @Observable already signals that state changes are intended to be observed (and in practice, usually by views), it seems natural that such types should also be main-actor isolated. Otherwise, we’re left with an implicit expectation that updates will always come from the main thread, but without the compiler’s help in enforcing that rule. This also ties into the concept of local reasoning that was emphasized in other Swift 6 talks (e.g. Beyond the basics of structured concurrency). With @MainActor, I can look at a view model and immediately know that all of its state is main-actor isolated. With only @Observable, that guarantee is left out, which feels like it weakens the clarity that Swift 6 is trying to promote. Would it be considered a best practice in Swift 6 to use both @Observable and @MainActor for UI-facing view models? Or is the intention that SwiftUI developers should rely on calling context to ensure main-thread updates, even if that means the compiler cannot enforce isolation? Thanks!
6
0
347
Aug ’25
Modelactors, Repository and bootloader
In iOS 26, should we have bootloader that runs the repo on startup - or should we have that inside tasks in root view? we have repos that runs as a «closed» functions, we dont throw but updates swiftdata and we use @query in the views. So what is best? and for the repo we should have a repo that runs the upserts manage relations eg? Should that run on a modelactor?
0
0
276
Sep ’25
Error accessing backing data on deleted item in detached task
I have been working on an app for the past few months, and one issue that I have encountered a few times is an error where quick subsequent deletions cause issues with detached tasks that are triggered from some user actions. Inside a Task.detached, I am building an isolated model context, querying for LineItems, then iterating over those items. The crash happens when accessing a Transaction property through a relationship. var byTransactionId: [UUID: [LineItem]] { return Dictionary(grouping: self) { item in item.transaction?.id ?? UUID() } } In this case, the transaction has been deleted, but the relationship existed when the fetch occurred, so the transaction value is non-nil. The crash occurs when accessing the id. This is the error. SwiftData/BackingData.swift:1035: Fatal error: This model instance was invalidated because its backing data could no longer be found the store. PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(backing: SwiftData.PersistentIdentifier.PersistentIdentifierBacking.managedObjectID(0xb43fea2c4bc3b3f5 &lt;x-coredata://A9EFB8E3-CB47-48B2-A7C4-6EEA25D27E2E/Transaction/p1756&gt;))) I see other posts about this error and am exploring some suggestions, but if anyone has any thoughts, they would be appreciated.
2
0
431
Nov ’25
Used Xcode AI to Clear 100+ Sendable Warnings
I have two apps in which I have fixed warnings on Sendable, however there's one app where I did not and it looks like the rent's come due with Xcode 26.0, as I am getting over 100 warnings about Sendable. On a lark, I let the AI work on the warnings. There were so many that I ran out of free ChatGPT time and had to wait 24 hours. But today I cleared every remaining warning, but did the app still work? I figured I'd have to trash this code and do it by hand. But to my surprise, the app is working properly so far. More testing needs to be done and I need to dig into the code to make sure it's right, but so far, so good.
1
0
167
Sep ’25
Potential Structural Swift Concurrency Issue: unsafeForcedSync called from Swift Concurrent context
I occasionally get this error in Xcode’s console: Potential Structural Swift Concurrency Issue: unsafeForcedSync called from Swift Concurrent context. What does this mean, and how can I resolve it? Googling it doesn’t turn up any results. This doesn't crash the app - it’s just an error diagnostic that I see in the Xcode console. The app keeps running before and after the issue. Is there a way I can set a breakpoint to catch this where it happens?
9
2
4.1k
Mar ’26
Waiting for an Async Result in a Synchronous Function
This comes up over and over, here on the forums and elsewhere, so I thought I’d post my take on it. If you have questions or comments, start a new thread here on the forums. Put it in the App & System Services > Processes & Concurrency subtopic and tag it with Concurrency. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Waiting for an Async Result in a Synchronous Function On Apple platforms there is no good way for a synchronous function to wait on the result of an asynchronous function. Lemme say that again, with emphasis… On Apple platforms there is no good way for a synchronous function to wait on the result of an asynchronous function. This post dives into the details of this reality. Prime Offender Imagine you have an asynchronous function and you want to call it from a synchronous function: func someAsynchronous(input: Int, completionHandler: @escaping @Sendable (_ output: Int) -> Void) { … processes `input` asynchronously … … when its done, calls the completion handler with the result … } func mySynchronous(input: Int) -> Int { … calls `someAsynchronous(…)` … … waits for it to finish … … results the result … } There’s no good way to achieve this goal on Apple platforms. Every approach you might try has fundamental problems. A common approach is to do this working using a Dispatch semaphore: func mySynchronous(input: Int) -> Int { fatalError("DO NOT WRITE CODE LIKE THIS") let sem = DispatchSemaphore(value: 0) var result: Int? = nil someAsynchronous(input: input) { output in result = output sem.signal() } sem.wait() return result! } Note This code produces a warning in the Swift 5 language mode which turns into an error in the Swift 6 language mode. You can suppress that warning with, say, a Mutex. I didn’t do that here because I’m focused on a more fundamental issue here. This code works, up to a point. But it has unavoidable problems, ones that don’t show up in a basic test but can show up in the real world. The two biggest ones are: Priority inversion Thread pools I’ll cover each in turn. Priority Inversion Apple platforms have a mechanism that helps to prevent priority inversion by boosting the priority of a thread if it holds a resource that’s needed by a higher-priority thread. The code above defeats that mechanism because there’s no way for the system to know that the threads running the work started by someAsynchronous(…) are being waited on by the thread blocked in mySynchronous(…). So if that blocked thread has a high-priority, the system can’t boost the priority of the threads doing the work. This problem usually manifests in your app failing to meet real-time goals. An obvious example of this is scrolling. If you call mySynchronous(…) from the main thread, it might end up waiting longer than it should, resulting in noticeable hitches in the scrolling. Threads Pools A synchronous function, like mySynchronous(…) in the example above, can be called by any thread. If the thread is part of a thread pool, it consumes a valuable resource — that is, a thread from the pool — for a long period of time. The raises the possibility of thread exhaustion, that is, where the pool runs out of threads. There are two common thread pools on Apple platforms: Dispatch Swift concurrency These respond to this issue in different ways, both of which can cause you problems. Dispatch can choose to over-commit, that is, start a new worker thread to get work done while you’re hogging its existing worker threads. This causes two problems: It can lead to thread explosion, where Dispatch starts dozens and dozens of threads, which all end up blocked. This is a huge waste of resources, notably memory. Dispatch has an hard limit to how many worker threads it will create. If you cause it to over-commit too much, you’ll eventually hit that limit, putting you in the thread exhaustion state. In contrast, Swift concurrency’s thread pool doesn’t over-commit. It typically has one thread per CPU core. If you block one of those threads in code like mySynchronous(…), you limit its ability to get work done. If you do it too much, you end up in the thread exhaustion state. WARNING Thread exhaustion may seem like just a performance problem, but that’s not the case. It’s possible for thread exhaustion to lead to a deadlock, which blocks all thread pool work in your process forever. There’s a trade-off here. Swift concurrency doesn’t over-commit, so it can’t suffer from thread explosion but is more likely deadlock, and vice versa for Dispatch. Bargaining Code like the mySynchronous(…) function shown above is fundamentally problematic. I hope that the above has got you past the denial stage of this analysis. Now let’s discuss your bargaining options (-: Most folks don’t set out to write code like mySynchronous(…). Rather, they’re working on an existing codebase and they get to a point where they have to synchronously wait for an asynchronous result. At that point they have the choice of writing code like this or doing a major refactor. For example, imagine you’re calling mySynchronous(…) from the main thread in order to update a view. You could go down the problematic path, or you could refactor your code so that: The current value is always available to the main thread. The asynchronous code updates that value in an observable way. The main thread code responds to that notification by updating the view from the current value. This refactoring may or may not be feasible given your product’s current architecture and timeline. And if that’s the case, you might end up deploying code like mySynchronous(…). All engineering is about trade-offs. However, don’t fool yourself into thinking that this code is correct. Rather, make a note to revisit this choice in the future. Async to Async Finally, I want to clarify that the above is about synchronous functions. If you have a Swift async function, there is a good path forward. For example: func mySwiftAsync(input: Int) async -> Int { let result = await withCheckedContinuation { continuation in someAsynchronous(input: input) { output in continuation.resume(returning: output) } } return result } This looks like it’s blocking the current thread waiting for the result, but that’s not what happens under the covers. Rather, the Swift concurrency worker thread that calls mySwiftAsync(…) will return to the thread pool at the await. Later, when someAsynchronous(…) calls the completion handler and you resume the continuation, Swift will grab a worker thread from the pool to continue running mySwiftAsync(…). This is absolutely normal and doesn’t cause the sorts of problems you see with mySynchronous(…). IMPORTANT To keep things simple I didn’t implement cancellation in mySwiftAsync(…). In a real product it’s important to support cancellation in code like this. See the withTaskCancellationHandler(operation:onCancel:isolation:) function for the details.
0
0
1k
Oct ’25
Error `Type of expression is ambiguous without a type annotation` when trying to create a Task.
Hi, I've got this view model that will do a search using a database of keywords. It worked fine when the SearchEngine wasn't an actor but a regular class and the SearchResult wasn't a Sendable. But when I changed them, it returned Type of expression is ambiguous without a type annotation error at line 21 ( searchTask = Task {). What did I do wrong here? Thanks. protocol SearchableEngine: Actor { func searchOrSuggest(from query: String) -> SearchResult? func setValidTitles(_ validTitles: [String]) } @MainActor final class SearchViewModel: ObservableObject { @Published var showSuggestion: Bool = false @Published var searchedTitles: [String] = [] @Published var suggestedKeyword: String? = nil private var searchTask: Task<Void, Never>? private let searchEngine: SearchableEngine init(searchEngine: SearchableEngine) { self.searchEngine = searchEngine } func search(_ text: String) { searchTask?.cancel() searchTask = Task { guard !Task.isCancelled else { return } let searchResult = await searchEngine.searchOrSuggest(from: text) ?? .notFound guard !Task.isCancelled else { return } await MainActor.run { switch searchResult { case let .searchItems(_, items): showSuggestion = false searchedTitles = items.map(\.title) suggestedKeyword = nil case let .suggestion(keyword, _, items): showSuggestion = true searchedTitles = items.map(\.title) suggestedKeyword = keyword case .notFound: showSuggestion = false searchedTitles = [] suggestedKeyword = nil } } } } }
1
0
760
Oct ’25
Structured concurrency + preconcurrency API (SFAuthorizationPluginView)
I'm having trouble dealing with concurrency with the SFAuthorizationPluginView. Does anybody know how this can be solved? https://developer.apple.com/documentation/securityinterface/sfauthorizationpluginview The crux of it is: If I inherit an object as part of an API, and the API is preconcurrency, and thus is nonisolated (but in reality is @MainActor), how do I return a @MainActor GUI element? https://developer.apple.com/documentation/securityinterface/sfauthorizationpluginview/firstresponder() The longer story: I made my view class inherit SFAuthorizationPluginView. The API is preconcurrency (but not marked as preconcurrency) I started using concurrency in my plugin to retrieve data over XPC. (https://developer.apple.com/documentation/xpc/xpcsession + https://developer.apple.com/documentation/swift/withcheckedthrowingcontinuation(isolation:function:_:)) Once I retrieve the data over XPC, I need to post it on GUI, hence I've set my view class as @MainActor in order to do the thread switch. Swift compiler keeps complaining: override func firstResponder() -&gt; NSResponder? { return usernameField } "Main actor-isolated property 'usernameField' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode" override func firstResponder() -&gt; NSResponder? { MainActor.assumeIsolated { return usernameField } } "Sending 'self' risks causing data races; this is an error in the Swift 6 language mode" I think fundamentally, the API is forcing me to give away a @MainActor variable through a nonisolated function, and there is no way to shut up the compiler. I've tried @preconcurrency and it has no effect as far as I can tell. I've also tried marking the function explicitly as nonisolated. The rest of the API are less problematic, but returning a GUI variable is exceptionally difficult.
Replies
2
Boosts
0
Views
805
Activity
Jul ’25
Playground Macro Raises Error when compiled with Swift 6
In my Xcode app, I was attempting to use the #Playground macro to play around with some of the Foundation Model features to see if they would work for my iOS app. However, every time I used a #Playground macro, even if it was empty, it would receive the following error: /var/folders/q2/x5b9x0y161bb2l_0yj1_j6wm0000gn/T/swift-generated-sources/@__swiftmacro_20PlaygroundMacroIssue0022ContentViewswift_tiAIefMX26_0_33_B691877350F20F2DFC040B9E585F4D10Ll0A0fMf_.swift:51:5 Main actor-isolated let '$s20PlaygroundMacroIssue0022ContentViewswift_tiAIefMX26_0_33_B691877350F20F2DFC040B9E585F4D10Ll0A0fMf_23PlaygroundContentRecordfMu_' can not be referenced from a nonisolated context Here are my Xcode and system versions: Mac is running the first public beta of Tahoe. iOS Simulator is running 26.0 dev beta 4. Xcode is Xcode 26 beta 4. So, I went to try to reproduce the error in a blank iOS app project (the error above is the one that I reproduced in that project). Here are the steps that I took. I created a new iOS project in Xcode 26. I went into the ContentView.swift that was created for me and imported the Playgrounds module and created a blank #Playground at the bottom of the file. I then compiled the project and it ran just fine. To try to find out what the issue was, I looked at the concurrency settings. In my real app, Strict Concurrency Checking was set to Complete but was Minimal in my test project. So I went and changed that setting in my real app and it didn't fix anything. Next, I looked at the Swift Version, which turned out to be the culprit. My test app was running Swift 5 whereas the real app was running Swift 6. It seems to have crashed while running Swift 6, not 5. I have trouble understanding what the error is saying. I have tried using the Code Intelligence feature to fix the bug but it hasn't helped. Has anyone here experienced a similar bug? Is there something I can do to fix it or is this an error in Xcode that should be reported? I have attached an iCloud link to my test project if anybody wants to see if they can reproduce the issue: here Thanks!
Replies
2
Boosts
0
Views
236
Activity
Aug ’25
Expected behavior from apps when MacOS goes to sleep
Every time macOS goes to sleep the processes get suspended which is expected. But during the sleep period, all processes keep coming back and they all get a small execution window where they make some n/w requests. Regardless of what power settings i have. It also does not matter whether my app is a daemon or not Is there any way that i can disable this so that when system is in sleep, it stays in suspended, no intermittent execution window? I have tried disabling Wake for network access setting but processes still keep getting intermittent execution window. Is there any way that i can prevent my app from coming back while in sleep. I don't want my app to get execution window, perform some executions and then get suspended not knowing when it will get execution window again?
Replies
1
Boosts
0
Views
155
Activity
Aug ’25
`.task(id:_:)` starting in the `Task.isCancelled` state
I'm running into a weird SwiftUI concurrency issue that only seems to happen on a real device (iOS 18.5 in my case), and not in simulator. I have a NavigationSplitView where the Detail view uses .task(id:_:) to perform some async work upon appearance (in my real-world case, a map snapshot). When running this on a real device, the first execution of the task works as expected. However, any task subsequent executions, even ones for the same id, always start in the Task.isCancelled state. Is there something about .task(id:_:) that I'm misunderstanding, or have I stumbled upon a serious bug here? import SwiftUI struct ContentView: View { var body: some View { TaskBugSplitView() } } struct TestItem: Identifiable, Hashable { var id: Int var name: String } struct TaskBugSplitView: View { @State private var selectedItemIndex: [TestItem].Index? @State private var testItems: [TestItem] = [ TestItem(id: 1, name: "First Item"), TestItem(id: 2, name: "Second Item"), TestItem(id: 3, name: "Third Item"), TestItem(id: 4, name: "Fourth Item"), TestItem(id: 5, name: "Fifth Item") ] var body: some View { NavigationSplitView { List(testItems.indices, id: \.self, selection: $selectedItemIndex) { item in Text(testItems[item].name) } } detail: { if let selectedItemIndex { TaskBugDetailView(item: testItems[selectedItemIndex]) } else { Text("Select an item") .foregroundStyle(.secondary) } } } } struct TaskBugDetailView: View { @State var item: TestItem @State private var taskResult = "Not started" var body: some View { VStack(spacing: 20) { Text("Item: \(item.name)") .font(.title2) Text("Task Result:") .font(.headline) Text(taskResult) .foregroundStyle(taskResult.contains("CANCELLED") ? .red : .primary) Spacer() } .padding() .navigationTitle(item.name) .task(id: item.id) { // BUG: On real devices, Task.isCancelled is true immediately for all tasks // after the first successful one, even though the ID has changed if Task.isCancelled { taskResult = "CANCELLED at start" print("Task cancelled at start for item \(item.id)") return } taskResult = "SUCCESS" print("Task completed successfully for item \(item.id)") } } }
Replies
2
Boosts
0
Views
159
Activity
Aug ’25
`awakeFromNib` and Approachable Concurrency
When attempting to compile an existing project with Swift 6, default isolation set to MainActor and approachable concurrency enabled, all awakeFromNib functions lead to the following compile error: "Main actor-isolated instance method 'awakeFromNib()' has different actor isolation from nonisolated overridden declaration" I've seen articles before approachable concurrency stating that one remedy is to wrap code within the function with MainActor.assumeIsolated{ }. However, that no longer addresses the error. One combination of changes that removes the error is doing the following: nonisolated override func awakeFromNib() { super.awakeFromNib() MainActor.assumeIsolated { ... } } Honestly, that's a mess. Long term, we are looking to remove all these functions, but does anyone have a better solution?
Replies
3
Boosts
0
Views
257
Activity
Aug ’25
TVTopShelfContentProvider and Swift 6 Concurrency
I have a TVTopShelfContentProvider that implements func loadTopShelfContent() async -&gt; (any TVTopShelfContent)? When running on Xcode 26 b5 I am seeing the following error in swift 6 mode. Non-Sendable type '(any TVTopShelfContent)?' cannot be returned from nonisolated override to caller of superclass instance method 'loadTopShelfContent()' I'm not sure exactly what's changed here as it used to compile just fine but it's unclear now how I can work-around this error or how the API is supposed to be used. The following definition is enough to trigger the error in Swift 6 language mode. import TVServices class ContentProvider: TVTopShelfContentProvider { override func loadTopShelfContent() async -&gt; (any TVTopShelfContent)? { return nil } } I can "fix" it by adding @preconcurrency to the TVServices import but it seems like this API is unusable currently? Or maybe it's user error on my part?
Replies
2
Boosts
0
Views
128
Activity
Aug ’25
Swift 6 conversion for IBOutlet
I'm struggling to convert Swift 5 to Swift 6. As advised in doc, I first turned strict concurrency ON. I got no error. Then, selected swift6… and problems pop up. I have a UIViewController with IBOutlets: eg a TextField. computed var eg duree func using UNNotification: func userNotificationCenter I get the following error in the declaration line of the func userNotificationCenter: Main actor-isolated instance method 'userNotificationCenter(_:didReceive:withCompletionHandler:)' cannot be used to satisfy nonisolated requirement from protocol 'UNUserNotificationCenterDelegate' So, I declared the func as non isolated. This func calls another func func2, which I had also to declare non isolated. Then I get error on the computed var used in func2 Main actor-isolated property 'duree' can not be referenced from a nonisolated context So I declared duree as nonsilated(unsafe). Now comes the tricky part. The computed var references the IBOutlet dureeField if dureeField.text == "X" leading to the error Main actor-isolated property 'dureeField' can not be referenced from a nonisolated context So I finally declared the class as mainActor and the textField as nonisolated @IBOutlet nonisolated(unsafe) weak var dureeField : UITextField! That silences the error (but declaring unsafe means I get no extra robustness with swift6) just to create a new one when calling dureeField.text: Main actor-isolated property 'text' can not be referenced from a nonisolated context Question: how to address properties inside IBOutlets ? I do not see how to declare them non isolated and having to do it on each property of each IBOutlet would be impracticable. The following did work, but will make code very verbose: if MainActor.assumeIsolated({dureeField.text == "X"}) { So I must be missing something.
Replies
5
Boosts
0
Views
789
Activity
Aug ’25
Should ModelActor be used to populate a view?
I'm working with SwiftData and SwiftUI and it's not clear to me if it is good practice to have a @ModelActor directly populate a SwiftUI view. For example when having to combine manual lab results and clinial results from HealthKit. The Clinical lab results are an async operation: @ModelActor actor LabResultsManager { func fetchLabResultsWithHealthKit() async throws -> [LabResultDto] { let manualEntries = try modelContext.fetch(FetchDescriptor<LabResult>()) let clinicalLabs = (try? await HealthKitService.getLabResults()) ?? [] return (manualEntries + clinicalLabs).sorted { $0.date > $1.date }.map { return LabResultDto(from: $0) } } } struct ContentView: View { @State private var labResults: [LabResultDto] = [] var body: some View { List(labResults, id: \.id) { result in VStack(alignment: .leading) { Text(result.testName) Text(result.date, style: .date) } } .task { do { let labManager = LabResultsManager() labResults = try await labManager.fetchLabResultsWithHealthKit() } catch { // Handle error } } } } EDIT: I have a few views that would want to use these labResults so I need an implementation that can be reused. Having to fetch and combine in each view will not be good practice. Can I pass a modelContext to a viewModel?
Replies
4
Boosts
0
Views
405
Activity
Aug ’25
SwiftData Fatal error: Editors must register their identifiers before invoking operations on this store
I have a UIKit app where I've adopted SwiftData and I'm struggling with a crash coming in from some of my users. I'm not able to reproduce it myself and as it only happens to a small fraction of my user base, it seems like a race condition of some sort. This is the assertion message: SwiftData/DefaultStore.swift:453: Fatal error: API Contract Violation: Editors must register their identifiers before invoking operations on this store SwiftData.DefaultStore: 00CF060A-291A-4E79-BEC3-E6A6B20F345E did not. (ID is unique per crash) This is the ModelActor that crashes: @available(iOS 17, *) @ModelActor actor ConsumptionDatabaseStorage: ConsumptionSessionStorage { struct Error: LocalizedError { var errorDescription: String? } private let sortDescriptor = [SortDescriptor(\SDConsumptionSession.startTimeUtc, order: .reverse)] static func createStorage(userId: String) throws -> ConsumptionDatabaseStorage { guard let appGroupContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: UserDefaults.defaultAppGroupIdentifier) else { throw Error(errorDescription: "Invalid app group container ID") } func createModelContainer(databaseUrl: URL) throws -> ModelContainer { return try ModelContainer(for: SDConsumptionSession.self, SDPriceSegment.self, configurations: ModelConfiguration(url: databaseUrl)) } let databaseUrl = appGroupContainer.appendingPathComponent("\(userId).sqlite") do { return self.init(modelContainer: try createModelContainer(databaseUrl: databaseUrl)) } catch { // Creating the model storage failed. Remove the database file and try again. try? FileManager.default.removeItem(at: databaseUrl) return self.init(modelContainer: try createModelContainer(databaseUrl: databaseUrl)) } } func isStorageEmpty() async -> Bool { (try? self.modelContext.fetchCount(FetchDescriptor<SDConsumptionSession>())) ?? 0 == 0 // <-- Crash here! } func sessionsIn(interval: DateInterval) async throws -> [ConsumptionSession] { let fetchDescriptor = FetchDescriptor(predicate: #Predicate<SDConsumptionSession> { sdSession in if let startDate = sdSession.startTimeUtc { return interval.start <= startDate && interval.end > startDate } else { return false } }, sortBy: self.sortDescriptor) let consumptionSessions = try self.modelContext.fetch(fetchDescriptor) // <-- Crash here! return consumptionSessions.map { ConsumptionSession(swiftDataSession: $0) } } func updateSessions(sessions: [ConsumptionSession]) async throws { if #unavailable(iOS 18) { // Price segments are duplicated if re-inserted so unfortunately we have to delete and reinsert sessions. // On iOS 18, this is enforced by the #Unique macro on SDPriceSegment. let sessionIds = Set(sessions.map(\.id)) try self.modelContext.delete(model: SDConsumptionSession.self, where: #Predicate<SDConsumptionSession> { sessionIds.contains($0.id) }) } for session in sessions { self.modelContext.insert(SDConsumptionSession(consumptionSession: session)) } if self.modelContext.hasChanges { try self.modelContext.save() } } func deleteAllSessions() async { if #available(iOS 18, *) { try? self.modelContainer.erase() } else { self.modelContainer.deleteAllData() } } } The actor conforms to this protocol: protocol ConsumptionSessionStorage { func isStorageEmpty() async -> Bool func hasCreditCardSessions() async -> Bool func sessionsIn(interval: DateInterval) async throws -> [ConsumptionSession] func updateSessions(sessions: [ConsumptionSession]) async throws func deleteAllSessions() async } The crash is coming in from line 30 and 41, in other words, when trying to fetch data from the database. There doesn't seem to be any common trait for the crashes. They occur across iOS versions and device types. Any idea what might cause this?
Replies
5
Boosts
0
Views
355
Activity
Aug ’25
Xcode 26: Sendable checking + NSManagedObjectContext.perform in Swift 6
I have some code which handles doing some computation on a background thread before updating Core Data NSManagedObjects by using the NSManagedObjectContext.perform functions. This code is covered in Sendable warnings in Xcode 26 (beta 6) because my NSManagedObject subclasses (autogenerated) are non-Sendable and NSManagedObjectContext.perform function takes a Sendable closure. But I can't really figure out what I should be doing. I realize this pattern is non-ideal for Swift concurrency, but it's what Core Data demands AFAIK. How do I deal with this? let moc = object.managedObjectContext! try await moc.perform { object.completed = true // Capture of 'object' with non-Sendable type 'MySpecialObject' in a '@Sendable' closure try moc.save() } Thanks in advance for your help!
Replies
1
Boosts
1
Views
187
Activity
Aug ’25
Equatable with default actor isolation of MainActor
I filed the following issue on swiftlang/swift on GitHub (Aug 8th), and a followup the swift.org forums, but not getting any replies. As we near the release of Swift 6.2, I want to know if what I'm seeing below is expected, or if it's another case where the compiler needs a fix. protocol P1: Equatable { } struct S1: P1 { } // Error: Conformance of 'S1' to protocol 'P1' crosses into main actor-isolated code an can cause data races struct S1Workaround: @MainActor P1 { } // OK // Another potential workaround if `Equatable` conformance can be moved to the conforming type. protocol P2 { } struct S2: Equatable, P2 { } // OK There was a prior compiler bug fix which addressed inhereted protocols regarding @MainActor. For Equatable, one still has to use @MainActoreven when the default actor isolation is MainActor. Also affects Hashable and any other protocol inheriting from Equatable.
Replies
3
Boosts
0
Views
1.2k
Activity
Aug ’25
Possible typo in concurrency diagram (WWDC25: Elevate an app with Swift concurrency)
Hello, While watching WWDC25: Code-along: Elevate an app with Swift concurrency at timestamp 25:48, I noticed something in the slide/diagram that might be incorrect. The diagram shows ExtractSticker twice, but based on the code context and spoken explanation, I think it was meant to be ExtractSticker and ExtractColor. Reasoning: The surrounding code and narration describe the use of async let and a Sendable Data object. From the flow, one task extracts a sticker while the other extracts a color, so it seems like the diagram is inconsistent. I do understand that with @concurrent, having two ExtractSticker operations on the same Data is technically possible (with two concurrent process executing their respective ExtractSticker) — but that would be a different meaning than what the talk was describing. Since concurrency is already a subtle and error-prone topic, I thought it was worth pointing this out. If I’m mistaken, I’d love clarification. Otherwise, this could be a small correction to keep things aligned and clearer for everyone. Minor point overall, but Swift 6’s concurrency model is doing a fantastic job at helping us write safer code—so thank you to the team for that! (Attaching screenshots for reference)
Replies
2
Boosts
0
Views
1.9k
Activity
Aug ’25
Foundation Model Inference in Background? Concurrency?
Hi, Are there rules around using Foundation Models: In a background task/session? Concurrently, i.e. a bunch simultaneously using Swift Concurrency? I couldn't find this in the docs (sorry if I missed it) so wondering what's supported and what the best practice is here. In case it matters, my primary platform is Vision Pro (so, M2).
Replies
2
Boosts
0
Views
1.3k
Activity
Aug ’25
Should SwiftUI view models in Swift 6 be both @Observable and @MainActor?
Hi, In the WWDC25 session Elevate an app with Swift concurrency (timestamps: 8:04 and later), the StickerViewModel is shown annotated with @Observable but not @MainActor. The narration mentions that updates happen on the main thread, but that guarantee is left implicit in the calling code. In Swift 6, though, one of the major benefits is stronger compiler enforcement against data races and isolation rules. If a view model were also annotated with @MainActor, then the compiler could enforce that observable state is only updated on the main actor, preventing accidental background mutations or updates that can cause data races between nonisolated and main actor-isolated uses. Since @Observable already signals that state changes are intended to be observed (and in practice, usually by views), it seems natural that such types should also be main-actor isolated. Otherwise, we’re left with an implicit expectation that updates will always come from the main thread, but without the compiler’s help in enforcing that rule. This also ties into the concept of local reasoning that was emphasized in other Swift 6 talks (e.g. Beyond the basics of structured concurrency). With @MainActor, I can look at a view model and immediately know that all of its state is main-actor isolated. With only @Observable, that guarantee is left out, which feels like it weakens the clarity that Swift 6 is trying to promote. Would it be considered a best practice in Swift 6 to use both @Observable and @MainActor for UI-facing view models? Or is the intention that SwiftUI developers should rely on calling context to ensure main-thread updates, even if that means the compiler cannot enforce isolation? Thanks!
Replies
6
Boosts
0
Views
347
Activity
Aug ’25
Modelactors, Repository and bootloader
In iOS 26, should we have bootloader that runs the repo on startup - or should we have that inside tasks in root view? we have repos that runs as a «closed» functions, we dont throw but updates swiftdata and we use @query in the views. So what is best? and for the repo we should have a repo that runs the upserts manage relations eg? Should that run on a modelactor?
Replies
0
Boosts
0
Views
276
Activity
Sep ’25
Error accessing backing data on deleted item in detached task
I have been working on an app for the past few months, and one issue that I have encountered a few times is an error where quick subsequent deletions cause issues with detached tasks that are triggered from some user actions. Inside a Task.detached, I am building an isolated model context, querying for LineItems, then iterating over those items. The crash happens when accessing a Transaction property through a relationship. var byTransactionId: [UUID: [LineItem]] { return Dictionary(grouping: self) { item in item.transaction?.id ?? UUID() } } In this case, the transaction has been deleted, but the relationship existed when the fetch occurred, so the transaction value is non-nil. The crash occurs when accessing the id. This is the error. SwiftData/BackingData.swift:1035: Fatal error: This model instance was invalidated because its backing data could no longer be found the store. PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(backing: SwiftData.PersistentIdentifier.PersistentIdentifierBacking.managedObjectID(0xb43fea2c4bc3b3f5 &lt;x-coredata://A9EFB8E3-CB47-48B2-A7C4-6EEA25D27E2E/Transaction/p1756&gt;))) I see other posts about this error and am exploring some suggestions, but if anyone has any thoughts, they would be appreciated.
Replies
2
Boosts
0
Views
431
Activity
Nov ’25
Used Xcode AI to Clear 100+ Sendable Warnings
I have two apps in which I have fixed warnings on Sendable, however there's one app where I did not and it looks like the rent's come due with Xcode 26.0, as I am getting over 100 warnings about Sendable. On a lark, I let the AI work on the warnings. There were so many that I ran out of free ChatGPT time and had to wait 24 hours. But today I cleared every remaining warning, but did the app still work? I figured I'd have to trash this code and do it by hand. But to my surprise, the app is working properly so far. More testing needs to be done and I need to dig into the code to make sure it's right, but so far, so good.
Replies
1
Boosts
0
Views
167
Activity
Sep ’25
Potential Structural Swift Concurrency Issue: unsafeForcedSync called from Swift Concurrent context
I occasionally get this error in Xcode’s console: Potential Structural Swift Concurrency Issue: unsafeForcedSync called from Swift Concurrent context. What does this mean, and how can I resolve it? Googling it doesn’t turn up any results. This doesn't crash the app - it’s just an error diagnostic that I see in the Xcode console. The app keeps running before and after the issue. Is there a way I can set a breakpoint to catch this where it happens?
Replies
9
Boosts
2
Views
4.1k
Activity
Mar ’26
Waiting for an Async Result in a Synchronous Function
This comes up over and over, here on the forums and elsewhere, so I thought I’d post my take on it. If you have questions or comments, start a new thread here on the forums. Put it in the App & System Services > Processes & Concurrency subtopic and tag it with Concurrency. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Waiting for an Async Result in a Synchronous Function On Apple platforms there is no good way for a synchronous function to wait on the result of an asynchronous function. Lemme say that again, with emphasis… On Apple platforms there is no good way for a synchronous function to wait on the result of an asynchronous function. This post dives into the details of this reality. Prime Offender Imagine you have an asynchronous function and you want to call it from a synchronous function: func someAsynchronous(input: Int, completionHandler: @escaping @Sendable (_ output: Int) -> Void) { … processes `input` asynchronously … … when its done, calls the completion handler with the result … } func mySynchronous(input: Int) -> Int { … calls `someAsynchronous(…)` … … waits for it to finish … … results the result … } There’s no good way to achieve this goal on Apple platforms. Every approach you might try has fundamental problems. A common approach is to do this working using a Dispatch semaphore: func mySynchronous(input: Int) -> Int { fatalError("DO NOT WRITE CODE LIKE THIS") let sem = DispatchSemaphore(value: 0) var result: Int? = nil someAsynchronous(input: input) { output in result = output sem.signal() } sem.wait() return result! } Note This code produces a warning in the Swift 5 language mode which turns into an error in the Swift 6 language mode. You can suppress that warning with, say, a Mutex. I didn’t do that here because I’m focused on a more fundamental issue here. This code works, up to a point. But it has unavoidable problems, ones that don’t show up in a basic test but can show up in the real world. The two biggest ones are: Priority inversion Thread pools I’ll cover each in turn. Priority Inversion Apple platforms have a mechanism that helps to prevent priority inversion by boosting the priority of a thread if it holds a resource that’s needed by a higher-priority thread. The code above defeats that mechanism because there’s no way for the system to know that the threads running the work started by someAsynchronous(…) are being waited on by the thread blocked in mySynchronous(…). So if that blocked thread has a high-priority, the system can’t boost the priority of the threads doing the work. This problem usually manifests in your app failing to meet real-time goals. An obvious example of this is scrolling. If you call mySynchronous(…) from the main thread, it might end up waiting longer than it should, resulting in noticeable hitches in the scrolling. Threads Pools A synchronous function, like mySynchronous(…) in the example above, can be called by any thread. If the thread is part of a thread pool, it consumes a valuable resource — that is, a thread from the pool — for a long period of time. The raises the possibility of thread exhaustion, that is, where the pool runs out of threads. There are two common thread pools on Apple platforms: Dispatch Swift concurrency These respond to this issue in different ways, both of which can cause you problems. Dispatch can choose to over-commit, that is, start a new worker thread to get work done while you’re hogging its existing worker threads. This causes two problems: It can lead to thread explosion, where Dispatch starts dozens and dozens of threads, which all end up blocked. This is a huge waste of resources, notably memory. Dispatch has an hard limit to how many worker threads it will create. If you cause it to over-commit too much, you’ll eventually hit that limit, putting you in the thread exhaustion state. In contrast, Swift concurrency’s thread pool doesn’t over-commit. It typically has one thread per CPU core. If you block one of those threads in code like mySynchronous(…), you limit its ability to get work done. If you do it too much, you end up in the thread exhaustion state. WARNING Thread exhaustion may seem like just a performance problem, but that’s not the case. It’s possible for thread exhaustion to lead to a deadlock, which blocks all thread pool work in your process forever. There’s a trade-off here. Swift concurrency doesn’t over-commit, so it can’t suffer from thread explosion but is more likely deadlock, and vice versa for Dispatch. Bargaining Code like the mySynchronous(…) function shown above is fundamentally problematic. I hope that the above has got you past the denial stage of this analysis. Now let’s discuss your bargaining options (-: Most folks don’t set out to write code like mySynchronous(…). Rather, they’re working on an existing codebase and they get to a point where they have to synchronously wait for an asynchronous result. At that point they have the choice of writing code like this or doing a major refactor. For example, imagine you’re calling mySynchronous(…) from the main thread in order to update a view. You could go down the problematic path, or you could refactor your code so that: The current value is always available to the main thread. The asynchronous code updates that value in an observable way. The main thread code responds to that notification by updating the view from the current value. This refactoring may or may not be feasible given your product’s current architecture and timeline. And if that’s the case, you might end up deploying code like mySynchronous(…). All engineering is about trade-offs. However, don’t fool yourself into thinking that this code is correct. Rather, make a note to revisit this choice in the future. Async to Async Finally, I want to clarify that the above is about synchronous functions. If you have a Swift async function, there is a good path forward. For example: func mySwiftAsync(input: Int) async -> Int { let result = await withCheckedContinuation { continuation in someAsynchronous(input: input) { output in continuation.resume(returning: output) } } return result } This looks like it’s blocking the current thread waiting for the result, but that’s not what happens under the covers. Rather, the Swift concurrency worker thread that calls mySwiftAsync(…) will return to the thread pool at the await. Later, when someAsynchronous(…) calls the completion handler and you resume the continuation, Swift will grab a worker thread from the pool to continue running mySwiftAsync(…). This is absolutely normal and doesn’t cause the sorts of problems you see with mySynchronous(…). IMPORTANT To keep things simple I didn’t implement cancellation in mySwiftAsync(…). In a real product it’s important to support cancellation in code like this. See the withTaskCancellationHandler(operation:onCancel:isolation:) function for the details.
Replies
0
Boosts
0
Views
1k
Activity
Oct ’25
Error `Type of expression is ambiguous without a type annotation` when trying to create a Task.
Hi, I've got this view model that will do a search using a database of keywords. It worked fine when the SearchEngine wasn't an actor but a regular class and the SearchResult wasn't a Sendable. But when I changed them, it returned Type of expression is ambiguous without a type annotation error at line 21 ( searchTask = Task {). What did I do wrong here? Thanks. protocol SearchableEngine: Actor { func searchOrSuggest(from query: String) -> SearchResult? func setValidTitles(_ validTitles: [String]) } @MainActor final class SearchViewModel: ObservableObject { @Published var showSuggestion: Bool = false @Published var searchedTitles: [String] = [] @Published var suggestedKeyword: String? = nil private var searchTask: Task<Void, Never>? private let searchEngine: SearchableEngine init(searchEngine: SearchableEngine) { self.searchEngine = searchEngine } func search(_ text: String) { searchTask?.cancel() searchTask = Task { guard !Task.isCancelled else { return } let searchResult = await searchEngine.searchOrSuggest(from: text) ?? .notFound guard !Task.isCancelled else { return } await MainActor.run { switch searchResult { case let .searchItems(_, items): showSuggestion = false searchedTitles = items.map(\.title) suggestedKeyword = nil case let .suggestion(keyword, _, items): showSuggestion = true searchedTitles = items.map(\.title) suggestedKeyword = keyword case .notFound: showSuggestion = false searchedTitles = [] suggestedKeyword = nil } } } } }
Replies
1
Boosts
0
Views
760
Activity
Oct ’25