Concurrency

RSS for tag

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

Posts under Concurrency tag

102 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Concurrency Resources
Swift Concurrency Resources: DevForums tags: Concurrency The Swift Programming Language Concurrency > Concurrency 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. 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
655
Nov ’23
C compiler lies about c11 support
The C compiler accepts the option '-std=c11' and responds by defining the define token '__STDC_VERSION__' = 201112 which thereby claims C11 support. Additionally, it DOES NOT define '__STDC_NO_THREADS__' and therefore the include headers <threads.h> and <stdatomic.h> should exist but they dont. The compiler is promising C11 threads, condition variables, ... support but does NOT provide it. This is NOT a link time problem, it is a compile time issue.
6
0
4.3k
Jul ’23
Conforming @MainActor class to Codable
How does one add Codable conformance to a class that needs to be isolated to the MainActor? For example, the following code gives compiler errors: @MainActor final class MyClass: Codable { var value: Int enum CodingKeys: String, CodingKey { case value } init(from decoder: Decoder) throws { // <-- Compiler error: Initializer 'init(from:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Decodable' let data = try decoder.container(keyedBy: CodingKeys.self) self.value = try data.decode(Int.self, forKey: .value) } func encode(to encoder: Encoder) throws { // <-- Compiler error: Instance method 'encode(to:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Encodable' var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) } } I'm definitely struggling to get my head around actors and @MainActor at the moment!
1
1
2.7k
Jan ’24
Why does a MainActor class / function not run on Main Thread?
When marking the ViewController and the function with @MainActor, the assertion to check that the UI is updated on main thread fails. How do I guarantee that a function is run on Main Thread when using @MainActor? Example code: import UIKit @MainActor class ViewController: UIViewController {     let updateObject = UpdateObject()     override func viewDidLoad() {         super.viewDidLoad()                  updateObject.fetchSomeData { [weak self] _ in             self?.updateSomeUI()         }     }     @MainActor     func updateSomeUI() {         assert(Thread.isMainThread) // Assertion failed!     } } class UpdateObject {     func fetchSomeData(completion: @escaping (_ success: Bool) -> Void) {         DispatchQueue.global().async {             completion(true)         }     } } Even changing DispatchQueue.global().async to Task.detached does not work. Tested with Xcode 13.2.1 and Xcode 13.3 RC
5
0
2.3k
Jan ’24
Problem Running multiple Async tasks in View
Hey there, I have a problem running multiply tasks in parallel in a SwiftUI view. struct ModelsView: View { @StateObject var tasks = TasksViewModel() var body: some View { NavigationView{ ScrollView { ForEach(Array(zip(tasks.tasks.indices, tasks.tasks)), id: \.0) { task in NavigationLink(destination: ModelView()) { ModelPreviewView(model_name: "3dobject.usdz") .onAppear { if task.0 == tasks.tasks.count - 2 { Task { print(tasks.tasks.count) await tasks.fetch_tasks(count: 4) } } } } } }.navigationTitle("3D modelle") }.onAppear{ Task { await tasks.fetch_tasks(count: 5) await tasks.watch_for_new_tasks() } } } } In my view, I spawn a task as soon as the View Appears which, first, fetches 5 tasks from the database (this works fine), and then it starts watching for new tasks. In the Scroll View, right before the bottom is reached, I start loading new tasks. The problem is, the asynchronous function fetch_tasks(count: 4) only gets continued if the asynchronous function watch_for_new_tasks() stops blocking. actor TasksViewModel: ObservableObject { @MainActor @Published private(set) var tasks : [Tasks.Task] = [] private var last_fetched_id : String? = nil func fetch_tasks(count: UInt32) async { do { let tasks_data = try await RedisClient.shared.xrevrange(streamName: "tasks", end: last_fetched_id ?? "+" , start: "-", count: count) last_fetched_id = tasks_data.last?.id let fetched_tasks = tasks_data.compactMap { Tasks.Task(from: $0.data) } await MainActor.run { withAnimation(.easeInOut) { self.tasks.append(contentsOf: fetched_tasks) } } } catch { print("Error fetching taskss \(error)") } } func watch_for_new_tasks() async { while !Task.isCancelled { do { let tasks_data = try await RedisClient.shared.xread(streams: "tasks", ids: "$") let new_tasks = tasks_data.compactMap { Tasks.Task(from: $0.data) } await MainActor.run { for new_task in new_tasks.reversed() { withAnimation { self.tasks.insert(new_task, at: 0) } } } } catch { print(error) } } } ... } The asynchronous function watch_for_new_tasks() uses RedisClient.shared.xread(streams: "tasks", ids: "$") which blocks until at least one tasks is added to the Redis Stream. I tried running the watch_for_new_tasks() on a Task.detached tasks, but that also blocks. To be honest, I have no idea why this blocks, and I could use your guy's help if you could. Thank you in Advance, Michael
1
0
1.3k
Oct ’23
Tasks shown "alive" in Instruments display even after they should have finished.
In my TestApp I run the following code, to calculate every pixel of a bitmap concurrently: private func generate() async {     for x in 0 ..< bitmap.width{         for y in 0 ..< bitmap.height{             let result = await Task.detached(priority:.userInitiated){                return iterate(x,y)             }.value             displayResult(result)         }     } } This works and does not give any warnings or runtime issues. After watching the WWDC talk "Visualize and optimize Swift concurrency" I used instruments to visualize the Tasks: The number of active tasks continuously raises until 2740 and stays constant at this value even after all 64000 pixels have been calculated and displayed. What am I doing wrong?
2
0
1.2k
Dec ’23
Swift Concurrency, Core Data, "partially thread-safe" types & Sendable conformance
Hi, Xcode warns me that NSPersistentContainer, NSManagedObjectContext, NSPersistentHistoryTransaction and NSPersistentHistoryToken are non-Sendable types and therefore cannot cross actor boundaries. These warnings occur even when I use @preconcurrency import CoreData (only works with Xcode 14.0 Beta, in Xcode 13.4.1, it says '@preconcurrency' attribute on module 'CoreData' is unused) I understand that types in Core Data have yet to be marked as Sendable when it makes sense. Although NSPersistentHistoryTransaction, and NSPersistentHistoryToken are reference types, they should qualify to be marked as Sendable in the future since these are immutable types, am I right? NSPersistentContainer provides variables and methods like viewContext and newBackgroundContext(). It would make sense that this type is thread-safe. However, I'm not sure about it, especially regarding its loadPersistentStores(completionHandler:) method. Is NSPersistentContainer (and its subclass NSPersistentCloudKitContainer) thread-safe and should it be marked as Sendable in the future? The case of and NSManagedObjectContext confuses me the most. Indeed, it has both thread-safe methods like perform(_:) and thread-unsafe methods like save(). Still, it should be possible to cross actor boundaries. Would such a "partially thread-safe" type quality to be marked as Sendable? If not, how can it cross actor boundaries? The reason I'm asking these questions is that I have a CoreDataStack type. It has mutable variables, such as var lastHistoryToken: NSPersistentHistoryToken?, needs to perform work without blocking the main thread, such as writing the token to a file, has async methods, uses notification observers, and needs to be marked as Sendable to be used by other controllers running on different actors. Since this type is related to back-end work, I made it an Actor. This type exposes the persistent container, and a method to create new background threads. However, I need to explicitly annotate all methods using await context.perform { ... } as nonisolated in this actor. Not doing so causes a data race to be detected at runtime. Is this a bug, and is making a Core Data stack an Actor the proper way to do it or is there a better solution? Any help would be greatly appreciated. Thanks. Xcode Configuration Xcode 13.4.1, Xcode 14.0 beta 5 The Xcode project is configured with Other Swift Flags set to -Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks.
4
2
2.6k
Oct ’23
AsyncPublisher of KeyValueObservingPublisher doesn't work
Hi, I'm trying to use async/await for KVO and it seems something is broken. For some reason, it doesn't go inside for in body when I'm changing the observed property. import Foundation import PlaygroundSupport class TestObj: NSObject {   @objc dynamic var count = 0 } let obj = TestObj() Task {   for await value in obj.publisher(for: \.count).values {     print(value)   } } Task.detached {   try? await Task.sleep(for: .microseconds(100))   obj.count += 1 } Task.detached {   try? await Task.sleep(for: .microseconds(200))   obj.count += 1 } PlaygroundPage.current.needsIndefiniteExecution = true Expected result: 0, 1, 2 Actual result: 0 Does anyone know what is wrong here?
2
1
2.1k
Feb ’24
Swift Async/Await, how to bring asynchronously calculated results back to main thread
I'm relatively new to Swift, and very new to concurrency via Async/Await, so please be patient. 😀 I'm having a hard time comprehending how to do complex operations asynchronously in background threads, and then in turn bring the results back to the main thread. I'm getting various errors along the lines of "Mutation of captured var 'personName' in concurrently-executing". I've paired the issue down as simply as possible as follows, and you'll see where the compiler gives the error message. I'd appreciate any advice on how to evolve my mental model to make this work. Thanks! Bruce import Foundation actor Person {     var myName = "Thomas Jefferson"     var name: String {         get {             return myName         }     } } func main() {     let person = Person()     var personName: String     print("start")     let nameTask = Task {         return await person.name     }     Task {         do {             personName = try await nameTask.result.get()             // Error: Mutation of captured var 'personName' in concurrently-executing code         } catch {             print("error!!!")         }     }     print("The person's name is \(personName)") } RunLoop.main.run() main()
4
0
3.1k
5d
Please Create a Sendable Version of CKRecord or Make CKRecord Sendable
CKRecord is a class which does not conform to the Sendable protocol. Its fields consist of NSStrings, NSData and others which are not Sendable. I understand that Apple is incrementally modifying objects to be sendable, but I am experiencing and I would assume others are experiencing a very large number of warnings (for now) about CKRecords and Sendable. It may be too much to make CKRecord Sendable and it may be too much to create a Sendable version of CKRecord, but it would be nice if it could at least be investigated. My particular situation is I have created a Protocol named CKMethods which some of my view controllers use to download and upload CKRecords. I suddenly have a large number of warnings about non-sendable types being sent from main actor-isolated context to non-isolated instance method. The CKRecords sent to and from the protocol do not get mutated and I have never had a problem with data races in the years that I have had this protocol. At some point, the warnings will probably become errors and I definitely do not want to get to that point. I am still coming up to speed on Swift Concurrency, so there may be a more simple solution than the one I am working on - creating a Sendable Struct for every CKRecord type that I have in my app and modifying all of the methods to pass the Struct instead of a CKRecord and convert the Struct to a CKRecord for upload and convert the CKRecord to the Struct for download.
3
1
1k
3w
Why isn't the View protocol @MainActor?
Hi, It is known that if a SwiftUI view contains an @ObservedObject or @StateObject property, the View will inherit @MainActor isolation from the property wrappers. Similarly, the body view-builder is also marked @MainActor. What I'm wondering is why the whole SwiftUI View protocol isn't marked @MainActor. It seems to be a deliberate decision, but AFAICT it would make a lot of sense for all data and operations defined in a view to have main-actor isolation unless marked nonisolated. I'm currently adding @MainActor annotations to an existing codebase, and it's a bit awkward that some views automatically gain this attribute one way or another, while others need it explicitly applied. Is there a rationale that can be shared, or is this something which may be revised in future versions of the framework?
1
6
1.3k
Jun ’24
async/await back deployment crash in system extension
The problem I have a MacOS app that hosts a content filtering system extension, like SimpleFirewall. The app has been in production for a couple years. I'm working on a new version, and in testing the release candidate, I'm getting a consistent crash that I believe is related to swift concurrency back deployment. Here are the key details: building using Xcode 14.2, from a machine running Monterrey, Swift 5.7.2 crash does not happen when building and testing from Xcode, locally crash does not happen on test machine running Ventura crash DOES happen always on a test machine running Big Sur only the root-user system extension crashes, not the host application the new version introduced async/await into the system extension crash report shows identical stack trace to well-known issue that had to do with concurrency back deployment Is there a known issue/limitation with concurrency back deployment in the context of a system extension? Is there any reason why async/await shouldn't work in that context when deployed to Big Sur? More details, context The key lines of the crash stack trace are: 0 libswiftCore.dylib 0x00007fff2cdacdc7 swift::ResolveAsSymbolicReference::operator()(swift::Demangle::__runtime::SymbolicReferenceKind, swift::Demangle::__runtime::Directness, int, void const*) + 55 1 libswiftCore.dylib 0x00007fff2cdcf2dd swift::Demangle::__runtime::Demangler::demangleSymbolicReference(unsigned char) + 141 2 libswiftCore.dylib 0x00007fff2cdcc2a8 swift::Demangle::__runtime::Demangler::demangleType(__swift::__runtime::llvm::StringRef, std::__1::function<swift::Demangle::__runtime::Node* (swift::Demangle::__runtime::SymbolicReferenceKind, swift::Demangle::__runtime::Directness, int, void const*)>) + 168 3 libswiftCore.dylib 0x00007fff2cdb25a4 swift_getTypeByMangledNameImpl(swift::MetadataRequest, __swift::__runtime::llvm::StringRef, void const* const*, std::__1::function<swift::TargetMetadata<swift::InProcess> const* (unsigned int, unsigned int)>, std::__1::function<swift::TargetWitnessTable<swift::InProcess> const* (swift::TargetMetadata<swift::InProcess> const*, unsigned int)>) + 516 4 libswiftCore.dylib 0x00007fff2cdafd6d swift::swift_getTypeByMangledName(swift::MetadataRequest, __swift::__runtime::llvm::StringRef, void const* const*, std::__1::function<swift::TargetMetadata<swift::InProcess> const* (unsigned int, unsigned int)>, std::__1::function<swift::TargetWitnessTable<swift::InProcess> const* (swift::TargetMetadata<swift::InProcess> const*, unsigned int)>) + 477 5 libswiftCore.dylib 0x00007fff2cdaff9b swift_getTypeByMangledNameInContext + 171 6 com.myorg.app.filter-extension 0x000000010db2b8b7 0x10db02000 + 170167 7 libdispatch.dylib 0x00007fff20516806 _dispatch_client_callout + 8 8 libdispatch.dylib 0x00007fff2051798c _dispatch_once_callout + 20 9 libswiftCore.dylib 0x00007fff2cdbe16a swift_once + 26 10 com.myorg.app.filter-extension 0x000000010db2c5e3 0x10db02000 + 173539 11 com.myorg.app.filter-extension 0x000000010dbbd708 0x10db02000 + 767752 12 com.myorg.app.filter-extension 0x000000010db073cc 0x10db02000 + 21452 13 com.apple.NetworkExtension 0x00007fff2dfdd4d8 -[NEExtensionProviderContext createWithCompletionHandler:] + 377 14 com.apple.Foundation 0x00007fff215a7c96 __NSXPCCONNECTION_IS_CALLING_OUT_TO_EXPORTED_OBJECT_S1__ + 10 15 com.apple.Foundation 0x00007fff21552b98 -[NSXPCConnection _decodeAndInvokeMessageWithEvent:flags:] + 2271 16 com.apple.Foundation 0x00007fff2150a049 message_handler + 206 17 libxpc.dylib 0x00007fff20406c24 _xpc_connection_call_event_handler + 56 18 libxpc.dylib 0x00007fff20405a9b _xpc_connection_mach_event + 938 The first five lines are identical to an issue from Xcode 13.2.1, discussed in depth on the swift forums: https://forums.swift.org/t/async-await-crash-on-ios14-with-xcode-13-2-1/54541 ...except I'm using Xcode 14.2. Which makes me think that it's not exactly the same bug, but another manifestation of a failure to link against the back-deployed currency lib, possibly having to do with the fact that the system extension isn't able to access the back-deployed lib. The archived app does have libswift_Concurrency.dylib at MyApp.app/Contents/Frameworks/libswift_Concurrency.dylib. What I've Tried I tested the workaround in the above mentioned thread, using lipo to remove arm64 arch, but it didn't work. I also tested adding -Xllvm -sil-disable-pass=alloc-stack-hoisting to Other Swift settings, as suggested in https://developer.apple.com/forums/thread/697070. I would greatly appreciate any assistance.
9
0
2.0k
Aug ’23
Observation and MainActor
Previously, it was recommended to use the @MainActor annotation for ObservableObject implementation. @MainActor final class MyModel: ObservableObject { let session: URLSession @Published var someText = "" init(session: URLSession) { self.session = session } } We could use this as either a @StateObject or @ObservedObject: struct MyView: View { @StateObject let model = MyModel(session: .shared) } By moving to Observation, I need to the @Observable macro, remove the @Published property wrappers and Switch @StateObject to @State: @MainActor @Observable final class MyModel { let session: URLSession var someText = "" init(session: URLSession) { self.session = session } } But switching from @StateObject to @State triggers me an error due to a call to main-actor isolated initialiser in a synchronous nonisolated context. This was not the case with @StateObject of @ObservedObject. To suppress the warning I could : mark the initializer as nonisolated but it is not actually what I want Mark the View with @MainActor but this sounds odd Both solutions does not sound nice to my eye. Did I miss something here?
9
3
4.4k
Apr ’24
Thread QOS class
I see this warning when my app runs: Thread running at QOS_CLASS_USER_INTERACTIVE waiting on a lower QoS thread running at QOS_CLASS_DEFAULT. Investigate ways to avoid priority inversions This is true; I know what is going on. I'd like this other thread to have a higher priority. But how do I set the "QOS class" for a thread? Searching developer.apple.com for QOS_CLASS_USER_INTERACTIVE doesn't find much. It seems that dispatch queues have priorities, but in this case I have a thread, not a dispatch queue. Any ideas?
8
0
3.7k
Jul ’23
Peculiar EXC_BAD_ACCESS, involving a Task
I had to update a simple piece of code, so it could be delayed by a few ms in some cases. This is how I tried to achieve that, by using a Task: class SomeClass { private var availableStuff : Set&lt;Stuff&gt; = [] func updateStuff(lookingFor prop: SomeProp, updatedThing: String, waiting: Duration = .zero) { Task { if waiting != .zero { try await Task.sleep(for: waiting) } if var stuff = availableStuff.first(where: { $0.prop == prop }) { stuff.thing = updatedThing // print(availableStuff) self.availableStuff.remove(stuff) self.availableStuff.insert(stuff) // BAD ACCESS here } } } } It did work before implementing the delay, but now it would crash at the insert statement (sometimes at remove). Naively, I put a print statement beforehand and to my surprise, this kept the crash from occurring at all! I switched on Address Sanitizer, now it doesn't crash, even w/o the print statement. Am I using the Task wrong, somehow? How can I further diagnose this, so it doesn't happen later in production? Or should I just leave the print in and hope for the best? Thanks!
1
0
927
Jul ’23
SwiftData background inserts using ModelActor do not trigger SwiftUI @Query view updates, but background deletes do
In the WWDC 23 lounge, this exchange with @Dave N (Apple) indicated that using ModelActor is the right way to do background work using swift concurrency. https://developer.apple.com/forums/thread/731338 I've figured out how to use this approach to do background work using swift concurrency (inside a Task), and example code is below for those who find it useful, however I'm not seeing view updates when the background work is complete. There seems to be no way to trigger a view update based on a @Query when inserts happen in a ModelActor’s context. However, if a delete happens on the ModelActor context, this DOES trigger a view redraw. I believe this is a bug because I expect the behavior to be the same for inserts and deletes. I've submitted this as Feedback FB12689036. Below is a minimal project which is the default SwiftData template, where the Add and Delete buttons point to a ModelActor instead of the main view ModelContext. You will see that using the addItem function in the ModelActor does not trigger a UI update in ContentView. However if you relaunch the app the added Item will be present. In contrast, using the delete function on the ModelActor context does trigger an immediate view update in ContentView. If this is intended behavior, we need a way to merge changes from background contexts, similar to what is described in the Core Data document “Loading and Displaying a Large Data Feed”: https://developer.apple.com/documentation/swiftui/loading_and_displaying_a_large_data_feed In Core Data we have automaticallyMergesChangesFromParent and mergeChanges(fromContextDidSave:) to do this manually. There seems to be no equivalent for Swift Data. If anyone has solved this problem of merging changes from other contexts, or can confirm that this is a bug, please let me know. import SwiftUI import SwiftData struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var items: [Item] @State private var simpleModelActor: SimpleModelActor! var body: some View { NavigationView { List { ForEach(items) { item in NavigationLink { Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))") } label: { Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) } } .onDelete(perform: deleteItems) } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } Text("Select an item") } .onAppear { simpleModelActor = SimpleModelActor(modelContainer: modelContext.container) } } private func addItem() { Task { await simpleModelActor.addItem() } } private func deleteItems(offsets: IndexSet) { Task { for index in offsets { await simpleModelActor.delete(itemWithID: items[index].objectID) } } } } import Foundation import SwiftData final actor SimpleModelActor: ModelActor { let executor: any ModelExecutor init(modelContainer: ModelContainer) { let modelContext = ModelContext(modelContainer) executor = DefaultModelExecutor(context: modelContext) } func addItem() { let newItem = Item(timestamp: Date()) context.insert(newItem) try! context.save() // this does not impact a re-display by the @Query in ContentView. I would have expected it to cause a view redraw. } func delete(itemWithID itemID: Item.ID) { let item = context.object(with: itemID) context.delete(object: item) // this DOES cause a view redraw in ContentView. It triggers an update by @Query. // try! context.save() // this makes do difference to view redraw behavior. } }
5
10
2.4k
Jul ’23
Using discardingTaskGroup to limit concurrent tasks?
I'm having trouble understanding the use case for discardingTaskGroup. In my app, I want to submit 10 concurrent image upload requests; usually, I'd just fire off 10 unstructured Task {} instances (I'm assuming this is fine) for image in images { Task { do { try await uploadImage(item: item, image: image) } catch { // Handle any errors } } } But then I thought I'd actually like to have a max of ~3 uploads concurrently, where I would prioritize the images that appear to the user earlier first. I know using group.next() in a taskGroup we can await on previous results and add tasks as required. But my task does not return data, rather it performs an action. So, it seems like the new discardingTaskGroup could be a useful API. Task { do { try await withThrowingDiscardingTaskGroup { group in for image in images { group.addTask { try await uploadImage(item: item, image: image) } } } } catch { // Handle any errors } } How can I convert this discarding task group code to only include a max of n tasks running concurrently? And is this even a reasonable use of the new API to begin with? Best, T
1
0
1k
Aug ’23
I think there's a logic error in Apple SwiftUI tutorial Scrumdinger.
Hi. In Apple's SwiftUI Tutorial Scrumdinger, there's a logic that read and save a file in asynchronous function to keep the App's UI responsive. The tutorial says, Reading from the file system can be slow. To keep the interface responsive, you’ll write an asynchronous function to load data from the file system. Making the function asynchronous lets the system efficiently prioritize updating the user interface instead of sitting idle and waiting while the file system reads data. And here's code. @MainActor class ScrumStore: ObservableObject { @Published var scrums: [DailyScrum] = [] func load() async throws { let task = Task<[DailyScrum], Error> { let fileURL = try Self.fileURL() guard let data = try? Data(contentsOf: fileURL) else { return [] } let dailyScrums = try JSONDecoder().decode([DailyScrum].self, from: data) return dailyScrums } let scrums = try await task.value } func save(scrums: [DailyScrum]) async throws { let task = Task { let data = try JSONEncoder().encode(scrums) let outfile = try Self.fileURL() try data.write(to: outfile) } _ = try await task.value } } But the problem i think here is that the ScrumStore is Mainactor isolated annotated, the 'load' and 'save' method execute their Tasks in the main thread, so I think there's not much benefit we can get comparing using a synchronous method. The proper way I think here is that use 'Task.detached' initializer instead of 'Task' initializer, so that the Task doesn't isolated in MainActor context. If there's anything I understand wrong or miss, please let me know. Apple's Scrumdinger Tutorial Link
1
0
504
Aug ’23
ModelActor Implementation Changes In Xcode 15 Beta 7
Hi all, There appears to be some changes to how ModelActors are implemented in Beta 7 of Xcode 15. In Beta 6, we had the DefaultModelExecutor object which we used to assign to the ModelActor's executor property. A simple example is shown below: final actor SimpleModelActor: ModelActor { let executor: any ModelExecutor init(modelContainer: ModelContainer) { let modelContext = ModelContext(modelContainer) executor = DefaultModelExecutor(context: modelContext) } func addItem() { let newItem = Item(timestamp: Date()) context.insert(newItem) try! context.save() } .... } However, it seems that the DefaultModelExecutor class has been removed for Beta 7, without any real replacement. Anyone know how to implement a ModelActor in the new beta? Thanks in advance.
2
0
1k
Aug ’23
Why isn't PhotosPickerItem Sendable? Is it thread-safe?
Currently, PhotosPickerItem cannot be used from async/await code safely, for example in Tasks etc., because it does not conform to Sendable. The public api has only two properties, both of which are of a Sendable type: UTType and String?. Is this something that's going to be changed so I can mark it as @unchecked Sendable in my code, or is there an actual underlying reason why PhotosPickerItem is not Sendable? PHAsset, PHAssetCollection, PHFetchRequest, PHObject are all sendable, because - similarly to PhotosPickerItem - they contain no actual image data, they are just a preliminary representation of an image in the Photos app.
0
3
597
Aug ’23