Concurrency

RSS for tag

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

Posts under Concurrency tag

168 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Concurrency Resources
Swift Concurrency Resources: DevForums tags: Concurrency The Swift Programming Language > Concurrency documentation Migrating to Swift 6 documentation WWDC 2022 Session 110351 Eliminate data races using Swift Concurrency — This ‘sailing on the sea of concurrency’ talk is a great introduction to the fundamentals. WWDC 2021 Session 10134 Explore structured concurrency in Swift — The table that starts rolling out at around 25:45 is really helpful. Swift Async Algorithms package Swift Concurrency Proposal Index DevForum post Why is flow control important? DevForums post Matt Massicotte’s blog Dispatch Resources: DevForums tags: Dispatch Dispatch documentation — Note that the Swift API and C API, while generally aligned, are different in many details. Make sure you select the right language at the top of the page. Dispatch man pages — While the standard Dispatch documentation is good, you can still find some great tidbits in the man pages. See Reading UNIX Manual Pages. Start by reading dispatch in section 3. WWDC 2015 Session 718 Building Responsive and Efficient Apps with GCD [1] WWDC 2017 Session 706 Modernizing Grand Central Dispatch Usage [1] Avoid Dispatch Global Concurrent Queues DevForums post Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" [1] These videos may or may not be available from Apple. If not, the URL should help you locate other sources of this info.
0
0
1.1k
1w
Using if statement in .overlay causes app to freeze when using withAnimation
I have an issue where a very specific configuration of .overlay, withAnimation, and a bindable state can freeze the app when the state changes. I've isolated the problematic source code into a sample project can be found here that demonstrates the issue: https://github.com/katagaki/IcyOverlay Steps to Reproduce To reproduce the issue, tap the 'Simulate Content Load' button. Once the progress bar has completed, a switch is toggled to hide the progress view, which causes the overlay to disappear, and the app to freeze. Any help and/or advice will be appreciated! Development Environment Xcode Version 16.2 (16C5032a), macOS 15.2(24C101) iOS SDK: 18.2 (22C146), Simulator: 18.2 (22C150)
1
0
114
3d
What are possible failures when using CLLocationUpdate.Updates AsyncSequence
Hello, I'm currently migrating my app location service to use the new CLLocationUpdate.Updates. I'm trying to understand what can fail in this AsyncSequence. Based on the previous CLError, I thought authorisation was one of them for example but it turns out that this is handled by the CLLocationUpdate where we can check different properties. So, is there a list of errors available somewhere? Thanks Axel, @alpennec
2
0
85
4d
Struggling with async/await: Fetching an image off the main thread
Hey everyone, I’m learning async/await and trying to fetch an image from a URL off the main thread to avoid overloading it, while updating the UI afterward. Before starting the fetch, I want to show a loading indicator (UI-related work). I’ve implemented this in two different ways using Task and Task.detached, and I have some doubts: Is using Task { @MainActor the better approach? I added @MainActor because, after await, the resumed execution might not return to the Task's original actor. Is this the right way to ensure UI updates are done safely? Does calling fetchImage() on @MainActor force it to run entirely on the main thread? I used an async data fetch function (not explicitly marked with any actor). If I were to use a completion handler instead, would the function run on the main thread? Is using Task.detached overkill here? I tried Task.detached to ensure the fetch runs on a non-main actor. However, it seems to involve unnecessary actor hopping since I still need to hop back to the main actor for UI updates. Is there any scenario where Task.detached would be a better fit? class ViewController : UIViewController{ override func viewDidLoad() { super.viewDidLoad() //MARK: First approch Task{@MainActor in showLoading() let image = try? await fetchImage() //Will the image fetch happen on main thread? updateImageView(image:image) hideLoading() } //MARK: 2nd approch Task{@MainActor in showLoading() let detachedTask = Task.detached{ try await self.fetchImage() } updateImageView(image:try? await detachedTask.value) hideLoading() } } func fetchImage() async throws -> UIImage { let url = URL(string: "https://via.placeholder.com/600x400.png?text=Example+Image")! //Async data function call let (data, response) = try await URLSession.shared.data(from: url) guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { throw URLError(.badServerResponse) } guard let image = UIImage(data: data) else { throw URLError(.cannotDecodeContentData) } return image } func showLoading(){ //Show Loader handling } func hideLoading(){ //Hides the loader } func updateImageView(image:UIImage?){ //Image view updated } }
4
0
357
1w
Core Data `context.performAndWait` in an actor
Hello. I am re-writing our way of storing data into Core Data in our app, so it can be done concurrently. The solution I opted for is to have a singleton actor that takes an API model, and maps it to a Core Data object and saves it. For example, to store an API order model, I have something like this: func store( order apiOrder: APIOrder, currentContext: NSManagedObjectContext? ) -> NSManagedObjectID? { let context = currentContext ?? self.persistentContainer.newBackgroundContext() // … } In the arguments, there is a context you can pass, in case you need to create additional models and relate them to each other. I am not sure this is how you're supposed to do it, but it seemed to work. From what I've understood of Core Data and using multiple contexts, the appropriate way use them is with context.perform or context.performAndWait. However, since my storage helper is an actor, @globalActor actor Storage2 { … }, my storage's methods are actor-isolated. This gives me warnings / errors in Swift 6 when I try to pass the context for to another of my actor's methods. let context = … return context.performAndWait { // … if let apiBooking = apiOrder.booking { self.store(booking: apiBooking, context: context) /* causes warning: Sending 'context' risks causing data races; this is an error in the Swift 6 language mode 'self'-isolated 'context' is captured by a actor-isolated closure. actor-isolated uses in closure may race against later nonisolated uses Access can happen concurrently */ } // … } From what I understand this is because my methods are actor-isolated, but the closure of performAndWait does not execute in a thread safe environment. With all this, what are my options? I've extracted the store(departure:context:) into its own method to avoid duplicated code, but since I can't call it from within performAndWait I am not sure what to do. Can I ditch the performAndWait? Removing that makes the warning "go away", but I don't feel confident enough with Core Data to know the answer. I would love to get any feedback on this, hoping to learn!
0
0
142
1w
LocalAuthentication like Face ID crashes using swift 6 iOS 18.1
Hello, I have been implementing faceID authentication using LocalAuthentication, and I've noticed that if i use swift 5 this code compiles but when i change to swift 6 it gives me a crash saying this compile error: i have just created this project for this error purpose so this is my codebase: import LocalAuthentication import SwiftUI struct ContentView: View { @State private var isSuccess: Bool = false var body: some View { VStack { if isSuccess { Text("Succed") } else { Text("not succeed") } } .onAppear(perform: authenticate) } func authenticate() { let context = LAContext() var error: NSError? if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { let reason = "We need to your face to open the app" context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { sucexd, error in if sucexd { let success = sucexd Task { @MainActor [success] in isSuccess = success } } else { print(error?.localizedDescription as Any) } } } else { print(error as Any) } } } #Preview { ContentView() } also i have tried to not use the task block and also gives me the same error. i think could be something about the LAContext NSObject that is not yet adapted for swift 6 concurrency? also i tried to set to minimal but is the same error Im using xcode 16.1 (16B40) with M1 using MacOS Seqouia 15.0.1 Help.
2
1
211
1w
Why is flow control important?
One challenging aspect of Swift concurrency is flow control, aka backpressure. I was explaining this to someone today and thought it better to post that explanation here, for the benefit of all. If you have questions or comments, start a new thread in App & System Services > Processes & Concurrency and tag with Swift and Concurrency. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Why is flow control important? In Swift concurrency you often want to model data flows using AsyncSequence. However, that’s not without its challenges. A key issue is flow control, aka backpressure. Imagine you have a network connection with a requests property that returns an AsyncSequence of Request values. The core of your networking code might be a loop like this: func processRequests(connection: Connection) async throws { for try await request in connection.requests { let response = responseForRequest(request) try await connection.reply(with: response) } } Flow control is important in both the inbound and outbound cases. Let’s start with the inbound case. If the remote peer is generating requests very quickly, the network is fast, and responseForRequest(_:) is slow, it’s easy to fall foul of unbounded memory growth. For example, if you use AsyncStream to implement the requests property, its default buffering policy is .unbounded. So the code receiving requests from the connection will continue to receive them, buffering them in the async stream, without any bound. In the worst case scenario that might run your process out of memory. In a more typical scenario it might result in a huge memory spike. The outbound case is similar. Imagine that the remote peer keeps sending requests but stops receiving them. If the reply(with:) method isn’t implemented correctly, this might also result in unbounded memory growth. The solution to this problem is flow control. This flow control operates independently on the send and receive side: On the send side, the code sending responses should notice that the network connection has asserted flow control and stop sending responses until that flow control lifts. In an async method, like the reply(with:) example shown above, it can simply not return until the network connection has space to accept the reply. On the receive side, the code receiving requests from the connection should monitor how many are buffered. If that gets too big, it should stop receiving. That causes the requests to pile up in the connection itself. If the network connection implements flow control properly [1], this will propagate to the remote peer, which should stop generating requests. [1] TCP and QUIC both implement flow control. Use them! If you’re tempted to implement your own protocol directly on top of UDP, consider how it should handle flow control. Flow control and Network framework Network framework has built-in support for flow control. On the send side, it uses a ‘push’ model. When you call send(content:contentContext:isComplete:completion:) the connection buffers the message. However, it only calls the completion handler when it’s passed that message to the network for transmission [2]. If you send a message and don’t receive this completion callback, it’s time to stop sending more messages. On the receive side, Network framework uses a ‘pull’ model. The receiver calls a receive method, like receiveMessage(completion:), which calls a completion handler when there’s a message available. If you’ve already buffered too many messages, just stop calling this receive method. These techniques are readily adaptable to Swift concurrency using Swift’s CheckedContinuation type. That works for both send and receive, but there’s a wrinkle. If you want to model receive as an AsyncSequence, you can’t use AsyncStream. That’s because AsyncStream doesn’t support flow control. So, you’ll need to come up with your own AsyncSequence implementation [3]. [2] Note that this doesn’t mean that the data has made it to the remote peer, or has even been sent on the wire. Rather, it says that Network framework has successfully passed the data to the transport protocol implementation, which is then responsible for getting it to the remote peer. [3] There’s been a lot of discussion on Swift Evolution about providing such an implementation but none of that has come to fruition yet. Specifically: The Swift Async Algorithms package provides AsyncChannel, but my understanding is that this is not yet ready for prime time. I believe that the SwiftNIO folks have their own infrastructure for this. They’re driving this effort to build such support into Swift Async Algorithms. Avoid the need for flow control In some cases you can change your design to avoid the need for control. Imagine that your UI needs to show the state of a remote button. The network connection sends you a message every time the button is depressed or released. However, your UI only cares about the current state. If you forward every messages from the network to your UI, you have to worried about flow control. To eliminate that worry: Have your networking code translate the message to reflect the current state. Use AsyncStream with a buffering policy of .bufferingNewest(1). That way there’s only ever one value in the stream and, if the UI code is slow for some reason, while it might miss some transitions, it always knows about the latest state. 2024-12-13 Added a link to the MultiProducerSingleConsumerChannel PR. 2024-12-10 First posted.
0
0
272
1w
SwiftData Crash: Incorrect actor executor assumption.
I have this actor actor ConcurrentDatabase: ModelActor { nonisolated let modelExecutor: any ModelExecutor nonisolated let modelContainer: ModelContainer init(modelContainer: ModelContainer) { self.modelExecutor = DefaultSerialModelExecutor(modelContext: ModelContext(modelContainer)) self.modelContainer = modelContainer } /// Save pending changes in the model context. private func save() { if self.modelContext.hasChanges { do { try self.modelContext.save() } catch { ... } } } } I am getting a runtime crash on: try self.modelContext.save() when trying to insert something into the database and save Thread 1: Fatal error: Incorrect actor executor assumption; Expected same executor as MainActor. Can anyone explain why this is happening?
2
0
211
1w
Checking authorization status of AVCaptureDevice or CLLocation Manager gives runtime warnings in iOS 18
I have the following code in my ObservableObject class and recently XCode started giving purple coloured runtime issues with it (probably in iOS 18): Issue 1: Performing I/O on the main thread can cause slow launches. Issue 2: Interprocess communication on the main thread can cause non-deterministic delays. Issue 3: Interprocess communication on the main thread can cause non-deterministic delays. Here is the code: @Published var cameraAuthorization:AVAuthorizationStatus @Published var micAuthorization:AVAuthorizationStatus @Published var photoLibAuthorization:PHAuthorizationStatus @Published var locationAuthorization:CLAuthorizationStatus var locationManager:CLLocationManager override init() { // Issue 1 (Performing I/O on the main thread can cause slow launches.) cameraAuthorization = AVCaptureDevice.authorizationStatus(for: AVMediaType.video) micAuthorization = AVCaptureDevice.authorizationStatus(for: AVMediaType.audio) photoLibAuthorization = PHPhotoLibrary.authorizationStatus(for: .addOnly) //Issue 1: Performing I/O on the main thread can cause slow launches. locationManager = CLLocationManager() locationAuthorization = locationManager.authorizationStatus super.init() //Issue 2: Interprocess communication on the main thread can cause non-deterministic delays. locationManager.delegate = self } And also in route Change notification handler of AVAudioSession.routeChangeNotification, //Issue 3: Hangs - Interprocess communication on the main thread can cause non-deterministic delays. let categoryPlayback = (AVAudioSession.sharedInstance().category == .playback) I wonder how checking authorisation status can give these issues? What is the fix here?
1
0
185
2w
TaskExecutor and Swift 6 question
I have the following TaskExecutor code in Swift 6 and is getting the following error: //Error Passing closure as a sending parameter risks causing data races between main actor-isolated code and concurrent execution of the closure. May I know what is the best way to approach this? This is the default code generated by Xcode when creating a Vision Pro App using Metal as the Immersive Renderer. Renderer @MainActor static func startRenderLoop(_ layerRenderer: LayerRenderer, appModel: AppModel) { Task(executorPreference: RendererTaskExecutor.shared) { //Error let renderer = Renderer(layerRenderer, appModel: appModel) await renderer.startARSession() await renderer.renderLoop() } } final class RendererTaskExecutor: TaskExecutor { private let queue = DispatchQueue(label: "RenderThreadQueue", qos: .userInteractive) func enqueue(_ job: UnownedJob) { queue.async { job.runSynchronously(on: self.asUnownedSerialExecutor()) } } func asUnownedSerialExecutor() -> UnownedTaskExecutor { return UnownedTaskExecutor(ordinary: self) } static let shared: RendererTaskExecutor = RendererTaskExecutor() }
1
0
322
2w
Diffable Data Source Warning: Non-Thread Confined Updates
Hello, I’ve encountered a warning while working with UITableViewDiffableDataSource. Here’s the exact message: Warning: applying updates in a non-thread confined manner is dangerous and can lead to deadlocks. Please always submit updates either always on the main queue or always off the main queue - view=<UITableView: 0x7fd79192e200; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x600003f3c9f0>; backgroundColor = <UIDynamicProviderColor: 0x60000319bf80; provider = <NSMallocBlock: 0x600003f0ce70>>; layer = <CALayer: 0x6000036e8fa0>; contentOffset: {0, -116}; contentSize: {375, 20}; adjustedContentInset: {116, 0, 49, 0}; dataSource: <TtGC5UIKit29UITableViewDiffableDataSourceOC17ArticleManagement21DiscardItemsViewModel17SectionIdentifierSS: 0x600003228270>> OS: iOS Version: iOS 17+, Xcode Version: 16.0, Frameworks: UIKit, Diffable Data Source, View: UITableView used with a UITableViewDiffableDataSource. Steps to Reproduce: Using a diffable data source with a table view. Applying snapshot updates in the data source from a main thread. Warning occurs intermittently during snapshot application. Expected Behavior: The snapshot should apply without warnings, provided the updates are on a main thread. Actual Behavior: The warning suggests thread safety issues when applying updates on non-thread-confined queues. Questions: Is there a recommended best practice to handle apply calls in diffable data sources with thread safety in mind? Could this lead to potential deadlocks if not addressed? Note :- I confirm I am always reloading / reconfiguring data source on main thread. Please find the attached screenshots for the reference. Any guidance or clarification would be greatly appreciated!
0
0
259
2w
Crash occurs in both @MainActor classes and functions on iOS 14
Crash occurs in @MainActor class or function in iOS 14 Apps built and distributed targeting Xcode 16 version swift6 crash on iOS 14 devices. We create a static library and put it in our app's library. Crash occurs in all classes or functions of the static library (@MainActor in front). It does not occur from iOS / iPadOS 15. If you change the minimum supported version of the static library to iOS 11, a crash occurs, and if you change it to iOS 14, a crash does not occur. Is there a way to keep the minimum version of the static library at iOS 11 and prevent crashes?
1
0
193
2w
Bug fix
Hello, I have these two errors in this particular block of code: Capture of 'self' with non-sendable type 'MusicPlayer?' in a @Sendable closure and Capture of 'localUpdateProgress' with non-sendable type '(Double, Double) -> Void' in a @Sendable closure ` @MainActor func startProgressTimer(updateProgress: @escaping (Double, Double) -> Void) { timer?.invalidate() // Stop any existing timer let localUpdateProgress = updateProgress timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in guard let self = self, let audioPlayer = self.audioPlayer, let currentItem = audioPlayer.currentItem else { print("currentItem is nil or audioPlayer is unavailable") return } let currentTime = currentItem.currentTime().seconds let duration = currentItem.duration.seconds localUpdateProgress(currentTime, duration) } }` I've tried nearly every solution and can't think of one that works. Any help is greatly appreciated :)
1
0
197
2w
Threads with classic lock-based synchronization in SwiftUI in Xcode 16
Hi, I am stuck moving one of my projects from Xcode 15 to Xcode 16. This is a SwiftUI application that uses in some places classic Threads and locks/conditions for synchronization. I was hoping that in Swift 5 mode, I could compile and run this app also with Xcode 16 so that I can start migrating it towards Swift 6. Unfortunately, my application crashes via EXC_BREAKPOINT (code=1, subcode=0x1800eb31c) whenever some blocking operation e.g. condition.wait() or DispatchQueue.main.sync { ... } is invoked from within the same module (I haven't seen this happening for frameworks that use the same code that I linked in dynamically). I have copied an abstraction below that I am using, to give an example of the kind of code I am talking about. I have verified that Swift 5 is used, "strict concurrency checking" is set to "minimal", etc. I have not found a workaround and thus, I'm curious to hear if others were facing similar challenges? Any hints on how to proceed are welcome. Thanks, Matthias Example abstraction that is used in my app. It's needed because I have synchronous computations that require a large stack. It's crashing whenever condition.wait() is executed. public final class TaskSerializer: Thread { /// Condition to synchronize access to `tasks`. private let condition = NSCondition() /// The tasks queue. private var tasks = [() -> Void]() public init(stackSize: Int = 8_388_608, qos: QualityOfService = .userInitiated) { super.init() self.stackSize = stackSize self.qualityOfService = qos } /// Don't call directly; this is the main method of the serializer thread. public override func main() { super.main() while !self.isCancelled { self.condition.lock() while self.tasks.isEmpty { if self.isCancelled { self.condition.unlock() return } self.condition.wait() } let task = self.tasks.removeFirst() self.condition.unlock() task() } self.condition.lock() self.tasks.removeAll() self.condition.unlock() } /// Schedule a task in this serializer thread. public func schedule(task: @escaping () -> Void) { self.condition.lock() self.tasks.append(task) self.condition.signal() self.condition.unlock() } }
1
0
167
2w
MultiThreaded rendering with actor
Hi, I'm trying to modify the ScreenCaptureKit Sample code by implementing an actor for Metal rendering, but I'm experiencing issues with frame rendering sequence. My app workflow is: ScreenCapture -> createFrame -> setRenderData Metal draw callback -> renderAsync (getData from renderData) I've added timestamps to verify frame ordering, I also using binarySearch to insert the frame with timestamp, and while the timestamps appear to be in sequence, the actual rendering output seems out of order. // ScreenCaptureKit sample func createFrame(for sampleBuffer: CMSampleBuffer) async { if let surface: IOSurface = getIOSurface(for: sampleBuffer) { await renderer.setRenderData(surface, timeStamp: sampleBuffer.presentationTimeStamp.seconds) } } class Renderer { ... func setRenderData(surface: IOSurface, timeStamp: Double) async { _ = await renderSemaphore.getSetBuffers( isGet: false, surface: surface, timeStamp: timeStamp ) } func draw(in view: MTKView) { Task { await renderAsync(view) } } func renderAsync(_ view: MTKView) async { guard await renderSemaphore.beginRender() else { return } guard let frame = await renderSemaphore.getSetBuffers( isGet: true, surface: nil, timeStamp: nil ) else { await renderSemaphore.endRender() return } guard let texture = await renderSemaphore.getRenderData( device: self.device, surface: frame.surface) else { await renderSemaphore.endRender() return } guard let commandBuffer = _commandQueue.makeCommandBuffer(), let renderPassDescriptor = await view.currentRenderPassDescriptor, let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else { await renderSemaphore.endRender() return } // Shaders .. renderEncoder.endEncoding() commandBuffer.addCompletedHandler() { @Sendable (_ commandBuffer)-> Swift.Void in updateFPS() } // commit frame in actor let success = await renderSemaphore.commitFrame( timeStamp: frame.timeStamp, commandBuffer: commandBuffer, drawable: view.currentDrawable! ) if !success { print("Frame dropped due to out-of-order timestamp") } await renderSemaphore.endRender() } } actor RenderSemaphore { private var frameBuffers: [FrameData] = [] private var lastReadTimeStamp: Double = 0.0 private var lastCommittedTimeStamp: Double = 0 private var activeTaskCount = 0 private var activeRenderCount = 0 private let maxTasks = 3 private var textureCache: CVMetalTextureCache? init() { } func initTextureCache(device: MTLDevice) { CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, device, nil, &self.textureCache) } func beginRender() -> Bool { guard activeRenderCount < maxTasks else { return false } activeRenderCount += 1 return true } func endRender() { if activeRenderCount > 0 { activeRenderCount -= 1 } } func setTextureLoaded(_ loaded: Bool) { isTextureLoaded = loaded } func getSetBuffers(isGet: Bool, surface: IOSurface?, timeStamp: Double?) -> FrameData? { if isGet { if !frameBuffers.isEmpty { let frame = frameBuffers.removeFirst() if frame.timeStamp > lastReadTimeStamp { lastReadTimeStamp = frame.timeStamp print(frame.timeStamp) return frame } } return nil } else { // Set let frameData = FrameData( surface: surface!, timeStamp: timeStamp! ) // insert to the right position let insertIndex = binarySearch(for: timeStamp!) frameBuffers.insert(frameData, at: insertIndex) return frameData } } private func binarySearch(for timeStamp: Double) -> Int { var left = 0 var right = frameBuffers.count while left < right { let mid = (left + right) / 2 if frameBuffers[mid].timeStamp > timeStamp { right = mid } else { left = mid + 1 } } return left } // for setRenderDataNormalized func tryEnterTask() -> Bool { guard activeTaskCount < maxTasks else { return false } activeTaskCount += 1 return true } func exitTask() { activeTaskCount -= 1 } func commitFrame(timeStamp: Double, commandBuffer: MTLCommandBuffer, drawable: MTLDrawable) async -> Bool { guard timeStamp > lastCommittedTimeStamp else { print("Drop frame at commit: \(timeStamp) <= \(lastCommittedTimeStamp)") return false } commandBuffer.present(drawable) commandBuffer.commit() lastCommittedTimeStamp = timeStamp return true } func getRenderData( device: MTLDevice, surface: IOSurface, depthData: [Float] ) -> (MTLTexture, MTLBuffer)? { let _textureName = "RenderData" var px: Unmanaged<CVPixelBuffer>? let status = CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault, surface, nil, &px) guard status == kCVReturnSuccess, let screenImage = px?.takeRetainedValue() else { return nil } CVMetalTextureCacheFlush(textureCache!, 0) var texture: CVMetalTexture? = nil let width = CVPixelBufferGetWidthOfPlane(screenImage, 0) let height = CVPixelBufferGetHeightOfPlane(screenImage, 0) let result2 = CVMetalTextureCacheCreateTextureFromImage( kCFAllocatorDefault, self.textureCache!, screenImage, nil, MTLPixelFormat.bgra8Unorm, width, height, 0, &texture) guard result2 == kCVReturnSuccess, let cvTexture = texture, let mtlTexture = CVMetalTextureGetTexture(cvTexture) else { return nil } mtlTexture.label = _textureName let depthBuffer = device.makeBuffer(bytes: depthData, length: depthData.count * MemoryLayout<Float>.stride)! return (mtlTexture, depthBuffer) } } Above's my code - could someone point out what might be wrong?
7
0
332
Nov ’24
Potential of race condition in ARC?
I ran into a memory issue that I don't understand why this could happen. For me, It seems like ARC doesn't guarantee thread-safety. Let see the code below @propertyWrapper public struct AtomicCollection<T> { private var value: [T] private var lock = NSLock() public var wrappedValue: [T] { set { lock.lock() defer { lock.unlock() } value = newValue } get { lock.lock() defer { lock.unlock() } return value } } public init(wrappedValue: [T]) { self.value = wrappedValue } } final class CollectionTest: XCTestCase { func testExample() throws { let rounds = 10000 let exp = expectation(description: "test") exp.expectedFulfillmentCount = rounds @AtomicCollection var array: [Int] = [] for i in 0..<rounds { DispatchQueue.global().async { array.append(i) exp.fulfill() } } wait(for: [exp]) } } It will crash for various reasons (see screenshots below) I know that the test doesn't reflect typical application usage. My app is quite different from traditional app so the code above is just the simplest form for proof of the issue. One more thing to mention here is that array.count won't be equal to 10,000 as expected (probably because of copy-on-write snapshot) So my questions are Is this a bug/undefined behavior/expected behavior of Swift/Obj-c ARC? Why this could happen? Any solutions suggest? How do you usually deal with thread-safe collection (array, dict, set)?
2
0
305
Nov ’24
Seeking advice on building a multiplatform PDF viewer app
Hi everyone, I’m planning to develop a cross-platform PDF viewer app for iOS and macOS that will read PDFs from local storage and cloud services (Google Drive, iCloud, WorkDrive, etc.). The app should be read-only and display both the PDF content and its metadata (author, title, creation date, etc.). Key Features: View PDFs: Local and remote (cloud storage integration). Display metadata: Title, author, page count, etc. Cloud integration: Google Drive, iCloud, Zoho WorkDrive, etc. Read-only mode: No editing features, just viewing. Questions: Xcode Template: Should I use the Document App or Generic App template for this? PDF Metadata: Any built-in libraries for extracting PDF metadata in a read-only app? Performance: Any advice or documentation on handling large PDFs or cloud fetching efficiently? Thanks in advance for any advice or resources!
0
0
162
Nov ’24
VNCoreMLRequest Callback Not Triggered in Modified Video Classification App
Hi everyone, I'm working on integrating object recognition from live video feeds into my existing app by following Apple's sample code. My original project captures video and records it successfully. However, after integrating the Vision-based object detection components (VNCoreMLRequest), no detections occur, and the callback for the request is never triggered. To debug this issue, I’ve added the following functionality: Set up AVCaptureVideoDataOutput for processing video frames. Created a VNCoreMLRequest using my Core ML model. The video recording functionality works as expected, but no object detection happens. I’d like to know: How to debug this further? Which key debug points or logs could help identify where the issue lies? Have I missed any key configurations? Below is a diff of the modifications I’ve made to my project for the new feature. Diff of Changes: (Attach the diff provided above) Specific Observations: The captureOutput method is invoked correctly, but there is no output or error from the Vision request callback. Print statements in my setup function setForVideoClassify() show that the setup executes without errors. Questions: Could this be due to issues with my Core ML model compatibility or configuration? Is the VNCoreMLRequest setup incorrect, or do I need to ensure specific image formats for processing? Platform: Xcode 16.1, iOS 18.1, Swift 5, SwiftUI, iPhone 11, Darwin MacBook-Pro.local 24.1.0 Darwin Kernel Version 24.1.0: Thu Oct 10 21:02:27 PDT 2024; root:xnu-11215.41.3~2/RELEASE_X86_64 x86_64 Any guidance or advice is appreciated! Thanks in advance.
1
0
266
Nov ’24
Working correctly with actor annotated class
Hi, I have a complex structure of classes, and I'm trying to migrate to swift6 For this classes I've a facade that creates the classes for me without disclosing their internals, only conforming to a known protocol I think I've hit a hard wall in my knowledge of how the actors can exchange data between themselves. I've created a small piece of code that can trigger the error I've hit import SwiftUI import Observation @globalActor actor MyActor { static let shared: some Actor = MyActor() init() { } } @MyActor protocol ProtocolMyActor { var value: String { get } func set(value: String) } @MyActor func make(value: String) -> ProtocolMyActor { return ImplementationMyActor(value: value) } class ImplementationMyActor: ProtocolMyActor { private(set) var value: String init(value: String) { self.value = value } func set(value: String) { self.value = value } } @MainActor @Observable class ViewObserver { let implementation: ProtocolMyActor var value: String init() async { let implementation = await make(value: "Ciao") self.implementation = implementation self.value = await implementation.value } func set(value: String) { Task { await implementation.set(value: value) self.value = value } } } struct MyObservedView: View { @State var model: ViewObserver? var body: some View { if let model { Button("Loaded \(model.value)") { model.set(value: ["A", "B", "C"].randomElement()!) } } else { Text("Loading") .task { self.model = await ViewObserver() } } } } The error Non-sendable type 'any ProtocolMyActor' passed in implicitly asynchronous call to global actor 'MyActor'-isolated property 'value' cannot cross actor boundary Occurs in the init on the line "self.value = await implementation.value" I don't know which concurrency error happens... Yes the init is in the MainActor , but the ProtocolMyActor data can only be accessed in a MyActor queue, so no data races can happen... and each access in my ImplementationMyActor uses await, so I'm not reading or writing the object from a different actor, I just pass sendable values as parameter to a function of the object.. can anybody help me understand better this piece of concurrency problem? Thanks
1
0
299
Nov ’24
Swift Concurrency Proposal Index
Swift concurrency is an important part of my day-to-day job. I created the following document for an internal presentation, and I figured that it might be helpful for others. If you have questions or comments, put them in a new thread here on DevForums. Use the App & System Services > Processes & Concurrency topic area and tag it with both Swift and Concurrency. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Swift Concurrency Proposal Index This post summarises the Swift Evolution proposals that went into the Swift concurrency design. It covers the proposal that are implemented in Swift 6.0, plus a few additional ones that aren’t currently available. The focus is here is the Swift Evolution proposals. For general information about Swift concurrency, see the documentation referenced by Concurrency Resources. Swift 6.0 The following Swift Evolution proposals form the basis of the Swift 6.0 concurrency design. SE-0176 Enforce Exclusive Access to Memory link: SE-0176 notes: This defines the “Law of Exclusivity”, a critical foundation for both serial and concurrent code. SE-0282 Clarify the Swift memory consistency model ⚛︎ link: SE-0282 notes: This defines Swift’s memory model, that is, the rules about what is and isn’t allowed when it comes to concurrent memory access. SE-0296 Async/await link: SE-0296 introduces: async functions, async, await SE-0297 Concurrency Interoperability with Objective-C link: SE-0297 notes: Specifies how Swift imports an Objective-C method with a completion handler as an async method. Explicitly allows @objc actors. SE-0298 Async/Await: Sequences link: SE-0298 introduces: AsyncSequence, for await syntax notes: This just defines the AsyncSequence protocol. For one concrete implementation of that protocol, see SE-0314. SE-0300 Continuations for interfacing async tasks with synchronous code link: SE-0300 introduces: CheckedContinuation, UnsafeContinuation notes: Use these to create an async function that wraps a legacy request-reply concurrency construct. SE-0302 Sendable and @Sendable closures link: SE-0302 introduces: Sendable, @Sendable closures, marker protocols SE-0304 Structured concurrency link: SE-0304 introduces: unstructured and structured concurrency, Task, cancellation, CancellationError, withTaskCancellationHandler(…), sleep(…), withTaskGroup(…), withThrowingTaskGroup(…) notes: For the async let syntax, see SE-0317. For more ways to sleep, see SE-0329 and SE-0374. For discarding task groups, see SE-0381. SE-0306 Actors link: SE-0306 introduces: actor syntax notes: For actor-isolated parameters and the nonisolated keyword, see SE-0313. For global actors, see SE-0316. For custom executors and the Actor protocol, see SE-0392. SE-0311 Task Local Values link: SE-0311 introduces: TaskLocal SE-0313 Improved control over actor isolation link: SE-0313 introduces: isolated parameters, nonisolated SE-0314 AsyncStream and AsyncThrowingStream link: SE-0314 introduces: AsyncStream, AsyncThrowingStream, onTermination notes: These are super helpful when you need to publish a legacy notification construct as an async stream. For a simpler API to create a stream, see SE-0388. SE-0316 Global actors link: SE-0316 introduces: GlobalActor, MainActor notes: This includes the @MainActor syntax for closures. SE-0317 async let bindings link: SE-0317 introduces: async let syntax SE-0323 Asynchronous Main Semantics link: SE-0323 SE-0327 On Actors and Initialization link: SE-0327 notes: For a proposal to allow access to non-sendable isolated state in a deinitialiser, see SE-0371. SE-0329 Clock, Instant, and Duration link: SE-0329 introduces: Clock, InstantProtocol, DurationProtocol, Duration, ContinuousClock, SuspendingClock notes: For another way to sleep, see SE-0374. SE-0331 Remove Sendable conformance from unsafe pointer types link: SE-0331 SE-0337 Incremental migration to concurrency checking link: SE-0337 introduces: @preconcurrency, explicit unavailability of Sendable notes: This introduces @preconcurrency on declarations, on imports, and on Sendable protocols. For @preconcurrency conformances, see SE-0423. SE-0338 Clarify the Execution of Non-Actor-Isolated Async Functions link: SE-0338 note: This change has caught a bunch of folks by surprise and there’s a discussion underway as to whether to adjust it. SE-0340 Unavailable From Async Attribute link: SE-0340 introduces: noasync availability kind SE-0343 Concurrency in Top-level Code link: SE-0343 notes: For how strict concurrency applies to global variables, see SE-0412. SE-0374 Add sleep(for:) to Clock link: SE-0374 notes: This builds on SE-0329. SE-0381 DiscardingTaskGroups link: SE-0381 introduces: DiscardingTaskGroup, ThrowingDiscardingTaskGroup notes: Use this for task groups that can run indefinitely, for example, a network server. SE-0388 Convenience Async[Throwing]Stream.makeStream methods link: SE-0388 notes: This builds on SE-0314. SE-0392 Custom Actor Executors link: SE-0392 introduces: Actor protocol, Executor, SerialExecutor, ExecutorJob, assumeIsolated(…) Notes: For task executors, a closely related concept, see SE-0417. For custom isolation checking, see SE-0424. SE-0395 Observation link: SE-0395 introduces: Observation module, Observable notes: While this isn’t directly related to concurrency, it’s relationship to Combine, which is an important exising concurrency construct, means I’ve included it in this list. SE-0401 Remove Actor Isolation Inference caused by Property Wrappers link: SE-0401, commentary SE-0410 Low-Level Atomic Operations ⚛︎ link: SE-0410 introduces: Synchronization module, Atomic, AtomicLazyReference, WordPair SE-0411 Isolated default value expressions link: SE-0411, commentary SE-0412 Strict concurrency for global variables link: SE-0412 introduces: nonisolated(unsafe) notes: While this is a proposal about globals, the introduction of nonisolated(unsafe) applies to “any form of storage”. SE-0414 Region based Isolation link: SE-0414, commentary notes: To send parameters and results across isolation regions, see SE-0430. SE-0417 Task Executor Preference link: SE-0417, commentary introduces: withTaskExecutorPreference(…), TaskExecutor, globalConcurrentExecutor notes: This is closely related to the custom actor executors defined in SE-0392. SE-0418 Inferring Sendable for methods and key path literals link: SE-0418, commentary notes: The methods part of this is for “partial and unapplied methods”. SE-0420 Inheritance of actor isolation link: SE-0420, commentary introduces: #isolation, optional isolated parameters notes: This is what makes it possible to iterate over an async stream in an isolated async function. SE-0421 Generalize effect polymorphism for AsyncSequence and AsyncIteratorProtocol link: SE-0421, commentary notes: Previously AsyncSequence used an experimental mechanism to support throwing and non-throwing sequences. This moves it off that. Instead, it uses an extra Failure generic parameter and typed throws to achieve the same result. This allows it to finally support a primary associated type. Yay! SE-0423 Dynamic actor isolation enforcement from non-strict-concurrency contexts link: SE-0423, commentary introduces: @preconcurrency conformance notes: This adds a number of dynamic actor isolation checks (think assumeIsolated(…)) to close strict concurrency holes that arise when you interact with legacy code. SE-0424 Custom isolation checking for SerialExecutor link: SE-0424, commentary introduces: checkIsolation() notes: This extends the custom actor executors introduced in SE-0392 to support isolation checking. SE-0430 sending parameter and result values link: SE-0430, commentary introduces: sending notes: Adds the ability to send parameters and results between the isolation regions introduced by SE-0414. SE-0431 @isolated(any) Function Types link: SE-0431, commentary introduces: @isolated(any) attribute on function types, isolation property of functions values notes: This is laying the groundwork for SE-NNNN Closure isolation control. That, in turn, aims to bring the currently experimental @_inheritActorContext attribute into the language officially. SE-0433 Synchronous Mutual Exclusion Lock 🔒 link: SE-0433 introduces: Mutex SE-0434 Usability of global-actor-isolated types link: SE-0434, commentary notes: This loosen strict concurrency checking in a number of subtle ways. SE-0442 Allow TaskGroup's ChildTaskResult Type To Be Inferred link: SE-0442 notes: This represents a small quality of life improvement for withTaskGroup(…) and withThrowingTaskGroup(…). In Progress The proposals in this section didn’t make Swift 6.0. SE-0371 Isolated synchronous deinit link: SE-0371 availability: Swift 6.1 introduces: isolated deinit notes: Allows a deinitialiser to access non-sendable isolated state, lifting a restriction imposed by SE-0327. SE-0406 Backpressure support for AsyncStream link: SE-0406 availability: returned for revision notes: Currently AsyncStream has very limited buffering options. This was a proposal to improve that. This feature is still very much needed, but it’s not clear whether it’ll come back in anything resembling this guise. SE-0449 Allow nonisolated to prevent global actor inference link: SE-0449 availability: Swift 6.1 SE-NNNN Closure isolation control link: SE-NNNN introduces: @inheritsIsolation availability: not yet approved notes: This aims to bring the currently experimental @_inheritActorContext attribute into the language officially.
0
0
495
Nov ’24
How to break `while` loop and `deliver partial result to `View`?
I make some small program to make dots. Many of them. I have a Generator which generates dots in a loop: //reprat until all dots in frame while !newDots.isEmpty { virginDots = [] for newDot in newDots { autoreleasepool{ virginDots.append( contentsOf: newDot.addDots(in: size, allDots: &result, inSomeWay)) } newDots = virginDots } counter += 1 print ("\(result.count) dots in \(counter) grnerations") } Sometimes this loop needs hours/days to finish (depend of inSomeWay settings), so it would be very nice to send partial result to a View, and/or if result is not satisfying — break this loop and start over. My understanding of Tasks and Concurrency became worse each time I try to understand it, maybe it's my age, maybe language barier. For now, Button with {Task {...}} action doesn't removed Rainbow Wheel from my screen. Killing an app is wrong because killing is wrong. How to deal with it?
4
0
250
Nov ’24