Discover concurrency in SwiftUI

RSS for tag

Discuss the WWDC21 session Discover concurrency in SwiftUI.

Posts under wwdc21-10019 tag

11 Posts

Post

Replies

Boosts

Views

Activity

Loading Error in Landmarks tutorial
I am working through the "Creating and Combining Views" Swift UI Landmarks tutorial using MacOS 12.3 and XCode 13.3. When trying to preview the MapView I receive the error: |  LoadingError: failed to load library at path "/Users/Elizabeth_Russell/Library/Developer/Xcode/DerivedData/Landmarks-fifnagwlpuhontdywqyzptoyghbg/Build/Intermediates.noindex/Previews/Landmarks/Intermediates.noindex/Landmarks.build/Debug-iphonesimulator/Landmarks.build/Objects-normal/arm64/MapView.1.preview-thunk.dylib": Optional(dlopen(/Users/Elizabeth_Russell/Library/Developer/Xcode/DerivedData/Landmarks-fifnagwlpuhontdywqyzptoyghbg/Build/Intermediates.noindex/Previews/Landmarks/Intermediates.noindex/Landmarks.build/Debug-iphonesimulator/Landmarks.build/Objects-normal/arm64/MapView.1.preview-thunk.dylib, 0x0002): Symbol not found: _$s9Landmarks16MapView_PreviewsV8previewsQrvgZTx |    Referenced from: /Users/Elizabeth_Russell/Library/Developer/Xcode/DerivedData/Landmarks-fifnagwlpuhontdywqyzptoyghbg/Build/Intermediates.noindex/Previews/Landmarks/Intermediates.noindex/Landmarks.build/Debug-iphonesimulator/Landmarks.build/Objects-normal/arm64/MapView.1.preview-thunk.dylib |    Expected in: /Users/Elizabeth_Russell/Library/Developer/Xcode/UserData/Previews/Simulator Devices/49F2A163-EF87-47EC-B1F3-425A9742D1F7/data/Containers/Bundle/Application/0F7E6CF4-2589-42E5-B1C5-EE37941E4186/Landmarks.app/Landmarks) Can someone help me understand why the library is not being loaded? Thank you
1
0
743
Apr ’22
Where is the demo project?
I would like to compare what I'm doing (wrongly, it seems) to the video. Where's the demo project? In short, I'm seeing that the runtime is complaining with [SwiftUI] Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates. despite using @MainActor. And, it isn't clear where to instantiate the model object. I get a warning Expression requiring global actor 'MainActor' cannot appear in default-value expression of property '_manager'; this is an error in Swift 6 So while this is very promising, it is hard to discover the correct and modern way to implement asynchronous behavior in SwiftUI.
0
0
750
Mar ’22
Observing UserDefaults on iOS 13
Hello there, I stumbled on the issue of observing UserDefaults. My need is to "listening"/observing UD key named "com.apple.configuration.managed" which is responsible for reading provided MDM external plist. I checked that on the opened app it is possible to provide that plist, and app read this payload correctly. My problem is to observing that change, when plist is uploading. Requirement is to support iOS 13, this is why I can't use AppStorage. Despite using some similar solutions like: someone own implementation of AppStorage, and using StackOverflow solutions like this, it still doesn't work. My, I feel, the closest one solution was:   @objc dynamic var mdmConfiguration: Dictionary<String, String> {     get { (dictionary(forKey: MDM.ConfigurationPayloadKey) != nil) ? dictionary(forKey: MDM.ConfigurationPayloadKey)! as! Dictionary<String, String> : Dictionary<String, String>() }     set { setValue(newValue, forKey: MDM.ConfigurationPayloadKey)}   } } class MDMConfiguration: ObservableObject {       //@Binding private var bindedValue: Bool       @Published var configuration: Dictionary = UserDefaults.standard.mdmConfiguration {     didSet {       UserDefaults.standard.mdmConfiguration = configuration     //  bindedValue.toggle()     }   }   private var cancelable: AnyCancellable?   init() {  // init(toggle: Binding<Bool>) {     //_bindedValue = toggle     cancelable = UserDefaults.standard.publisher(for: \.mdmConfiguration)       .sink(receiveValue: { [weak self] newValue in         guard let self = self else { return }         if newValue != self.configuration { // avoid cycling !!           self.configuration = newValue         }       })   } } struct ContentView: View {       @State private var isConfigurationAvailable: Bool = false   @State private var showLoadingIndicator: Bool = true   @ObservedObject var configuration = MDMConfiguration()       var body: some View {           GeometryReader { geometry in               let width = geometry.size.width       let height = geometry.size.height                             VStack {         Text("CONTENT -> \(configuration.configuration.debugDescription)").padding()         Spacer()         if !configuration.configuration.isEmpty {           Text("AVAILABLE").padding()         } else {           Text("NIL NULL ZERO EMPTY")             .padding()         }       }        }   } } But it still doesn't ensure any changes in view, when I manually click on f.e. button, which prints the configuration in the console when it has uploaded, it does it well. Please help, my headache is reaching the zenith. I am a newbie in Swift development, maybe I did something weird and stupid. I hope so :D Thank in advance!
0
0
1.6k
Mar ’22
Swift 5.5 Concurrency: how to serialize async Tasks to replace an OperationQueue with maxConcurrentOperationCount = 1?
I’m currently migrating my app to use the concurrency model in Swift. I want to serialize Tasks to make sure they are executed one after the other (no paralellism). In my use case, I want to listen to notifications posted by the NotificationCenter and execute a Task every time a new notification is posted. But I want to make sure no previous task is running. It's the equivalent of using an OperationQueue with maxConcurrentOperationCount = 1. For example, I’m using CloudKit with Core Data in my app and I use persistent history tracking to determine what changes have occurred in the store. In this Synchronizing a Local Store to the Cloud Sample Code, Apple uses an operation queue for handling history processing tasks (in CoreDataStack). This OperationQueue has a maximum number of operations set to 1. private lazy var historyQueue: OperationQueue = { let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 return queue }() When a Core Data notification is received, a new task is added to this serial operation queue. So if many notifications are received, they will all be performed one after the other one in a serial way. @objc func storeRemoteChange(_ notification: Notification) { // Process persistent history to merge changes from other coordinators. historyQueue.addOperation { self.processPersistentHistory() } } In this Loading and Displaying a Large Data Feed Sample Code, Apple uses Tasks to handle history changes (in QuakesProvider). // Observe Core Data remote change notifications on the queue where the changes were made. notificationToken = NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: nil, queue: nil) { note in Task { await self.fetchPersistentHistory() } } I feel something is wrong in the second project as Tasks could happen in any order, and not necessarily in a serial order (contrary to the first project where the OperationQueue as a maxConcurrentOperationCount = 1). Should we use an actor somewhere to make sure the methods are serially called? I thought about an implementation like this but I’m not yet really comfortable with that: actor PersistenceStoreListener { let historyTokenManager: PersistenceHistoryTokenManager = .init() private let persistentContainer: NSPersistentContainer init(persistentContainer: NSPersistentContainer) { self.persistentContainer = persistentContainer } func processRemoteStoreChange() async { print("\(#function) called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") } } where the processRemoteStoreChange method would be called by when a new notification is received (AsyncSequence): notificationListenerTask = Task { let notifications = NotificationCenter.default.notifications(named: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator) for await _ in notifications { print("notificationListenerTask called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") await self.storeListener?.processRemoteStoreChange() } }
1
0
5.9k
Mar ’22
Using actors in a SwiftUI .task
Hi, having the concurrency checks (-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks) enabled I always get this warning, when trying to access/use an actor in a SwiftUI .task: "Cannot use parameter 'self' with a non-sendable type 'ContentView' from concurrently-executed code". What would be a correct implementation? Here's a minimal code-sample which produces this warning: import SwiftUI struct ContentView: View { @State var someVar = 5 var a1 = A1() var body: some View { Text("Hello, world!") .padding() .task { await a1.doSomething() } } } public actor A1 { func doSomething() { print("Hello") } }
1
0
2.4k
Feb ’22
@MainActor and the guarantee that the properties are only ever accessed from the main actor
In https://developer.apple.com/videos/play/wwdc2021-10019/?time=815 was said: "By adding the new @MainActor annotation to Photos, the compiler will guarantee that the properties (...) are only ever accessed from the main actor." What does it exactly mean? Let's consider the following example: @MainActor class ViewModel: ObservableObject {   @Published var text = "" } struct ContentView: View {   @StateObject private var viewModel = ViewModel()   var body: some View {     VStack {       Text(viewModel.text)         .padding()       Button("Refresh") {         Task.detached {           await updateText()         }       }     }   }   func updateText() async {     viewModel.text = "Hello, world"   } } Compiler doesn't complain. After button tap viewModel.text is changed from background actor and there is runtime warning: "Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates." So once again: How exactly @MainActor annotation and the compiler will guarantee that the properties are only ever accessed from the main actor?
0
0
1.4k
Jan ’22
Manipulating SwiftUI view state in a Task closure (button action)
In the session Discover concurrency in SwiftUI (at 19:48), the following sample code is presented as an example of starting an async task from a Button action (which is synchronous): struct SavePhotoButton: View { var photo: SpacePhoto @State private var isSaving = false var body: some View { Button { Task { isSaving = true await photo.save() isSaving = false } } label: { Text("Save") // … } // … } } (The code on the slide uses async { … }. I replaced this with the current Task { … } syntax.) I'm wondering if manipulating view state from inside the task closure like this is allowed. In fact, when you compile this with -Xfrontend -warn-concurrency, you get compiler warnings on all three lines in the task closure: Task { // warning: Cannot use parameter 'self' with a non-sendable type 'SavePhotoButton' from concurrently-executed code isSaving = true // same warning await photo.save() // same warning isSaving = false } You have to mark the view as @MainActor to get rid of the warnings: @MainActor struct SavePhotoButton: View { … } Questions: Can you confirm that the sample code is invalid without the @MainActor annotation on the view? How does the Task { … } closure guarantees that it runs on the main actor. I know that Task { … } inherits the current actor execution context, but how does that work here? My guess: View.body is annotated with @MainActor in the SwiftUI module interface Actor context inheritance is based on the lexical scope, so the fact that the Task { … } closure is inside body is enough for it to inherit that context, even if it's called from another context. Is this correct? Thanks.
0
0
2.2k
Nov ’21
Initialize app with an Async function | SwiftUI
I need my app to configure the backend at start, here's the function to do so: // Initializes Amplify final func configureAmplify() async { do { // Amplify.Logging.logLevel = .info let dataStore = AWSDataStorePlugin(modelRegistration: AmplifyModels()) let syncWithCloud = AWSAPIPlugin() let userAuth = AWSCognitoAuthPlugin() try Amplify.add(plugin: userAuth) try Amplify.add(plugin: dataStore) try Amplify.add(plugin: syncWithCloud) try Amplify.configure() print("Amplify initialized") } catch { print("Failed to initialize Amplify with \(error)") } } I tried placing it in the @main init like so: init() async { await networkController.configureAmplify() } but I get the following error: Type 'MyApplicationNameApp' does not conform to protocol 'App' I try to apply the suggestions after that which is to initialize it: init() { } but it seems odd, so now I have 2 init. What is going on here and what is the correct way to initialize multiple async functions at the start of the app, example: Code above (configure amplify) Check if user is logged in Set session etc Note: The init() async never gets called in the example above which is another problem within this question, so what is the correct way to initialize async function when the app starts.
1
0
4.3k
Aug ’21
Deduplication of Tasks
A pretty common piece of work I'd like to generalize a Task version of is deduplicating work in callback logic by stashing the equivalent callbacks to be called when the shared underlying work is done. I have a fairly naive version of this working as it's own Task/actor/async/await soup import Foundation public actor Dupes<Key: Hashable, Success, Failure: Error> {     private var tasks = [Key:Task<Success, Failure>]() } public extension Dupes where Failure == Error {     func async(key: Key, priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success) async throws -> Success {         if let task = tasks[key] {             return try await task.value         } else {             let task = Task(priority: priority) {                 try await operation()             }             tasks[key] = task             let data = try await task.value             tasks.removeValue(forKey: key)             return data         }     } } public extension Dupes where Failure == Never {     func async(key: Key, priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Success) async -> Success {         if let task = tasks[key] {             return await task.value         } else {             let task = Task(priority: priority) {                 await operation()             }             tasks[key] = task             let data = await task.value             tasks.removeValue(forKey: key)             return data         }     } } That can used like so if we had an async method that returns a value (bar()) based on some work that we know is shared based on the identifier 123 let foo = Foo() let dupes = Dupes<String, Int, Never>() Task.detached { await dupes.async(key: "123") {     await foo.bar() } } Task.detached { await dupes.async(key: "123") {     await foo.bar() } } In naive testing this seems to work. It feels really odd to be handing off to another actor for managing state that seems internal to whatever actor would need to avoid duplicate work. I tried defining similar methods on a custom actor or on an extension on Actor but passing the storage via keyPath or inout violates the mutability rules of actors (which to be fair makes sense). Is there an idiom for this kind of book keeping? A good real world example of this is network requests where I'd pass in a Hashable network request that makes or owns a URLRequest for me to hand off to URLSession. I don't want to download the same request twice and I don't want to write the same book keeping logic again and again.
0
0
912
Jul ’21
Loading Error in Landmarks tutorial
I am working through the "Creating and Combining Views" Swift UI Landmarks tutorial using MacOS 12.3 and XCode 13.3. When trying to preview the MapView I receive the error: |  LoadingError: failed to load library at path "/Users/Elizabeth_Russell/Library/Developer/Xcode/DerivedData/Landmarks-fifnagwlpuhontdywqyzptoyghbg/Build/Intermediates.noindex/Previews/Landmarks/Intermediates.noindex/Landmarks.build/Debug-iphonesimulator/Landmarks.build/Objects-normal/arm64/MapView.1.preview-thunk.dylib": Optional(dlopen(/Users/Elizabeth_Russell/Library/Developer/Xcode/DerivedData/Landmarks-fifnagwlpuhontdywqyzptoyghbg/Build/Intermediates.noindex/Previews/Landmarks/Intermediates.noindex/Landmarks.build/Debug-iphonesimulator/Landmarks.build/Objects-normal/arm64/MapView.1.preview-thunk.dylib, 0x0002): Symbol not found: _$s9Landmarks16MapView_PreviewsV8previewsQrvgZTx |    Referenced from: /Users/Elizabeth_Russell/Library/Developer/Xcode/DerivedData/Landmarks-fifnagwlpuhontdywqyzptoyghbg/Build/Intermediates.noindex/Previews/Landmarks/Intermediates.noindex/Landmarks.build/Debug-iphonesimulator/Landmarks.build/Objects-normal/arm64/MapView.1.preview-thunk.dylib |    Expected in: /Users/Elizabeth_Russell/Library/Developer/Xcode/UserData/Previews/Simulator Devices/49F2A163-EF87-47EC-B1F3-425A9742D1F7/data/Containers/Bundle/Application/0F7E6CF4-2589-42E5-B1C5-EE37941E4186/Landmarks.app/Landmarks) Can someone help me understand why the library is not being loaded? Thank you
Replies
1
Boosts
0
Views
743
Activity
Apr ’22
Where is the demo project?
I would like to compare what I'm doing (wrongly, it seems) to the video. Where's the demo project? In short, I'm seeing that the runtime is complaining with [SwiftUI] Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates. despite using @MainActor. And, it isn't clear where to instantiate the model object. I get a warning Expression requiring global actor 'MainActor' cannot appear in default-value expression of property '_manager'; this is an error in Swift 6 So while this is very promising, it is hard to discover the correct and modern way to implement asynchronous behavior in SwiftUI.
Replies
0
Boosts
0
Views
750
Activity
Mar ’22
Observing UserDefaults on iOS 13
Hello there, I stumbled on the issue of observing UserDefaults. My need is to "listening"/observing UD key named "com.apple.configuration.managed" which is responsible for reading provided MDM external plist. I checked that on the opened app it is possible to provide that plist, and app read this payload correctly. My problem is to observing that change, when plist is uploading. Requirement is to support iOS 13, this is why I can't use AppStorage. Despite using some similar solutions like: someone own implementation of AppStorage, and using StackOverflow solutions like this, it still doesn't work. My, I feel, the closest one solution was:   @objc dynamic var mdmConfiguration: Dictionary<String, String> {     get { (dictionary(forKey: MDM.ConfigurationPayloadKey) != nil) ? dictionary(forKey: MDM.ConfigurationPayloadKey)! as! Dictionary<String, String> : Dictionary<String, String>() }     set { setValue(newValue, forKey: MDM.ConfigurationPayloadKey)}   } } class MDMConfiguration: ObservableObject {       //@Binding private var bindedValue: Bool       @Published var configuration: Dictionary = UserDefaults.standard.mdmConfiguration {     didSet {       UserDefaults.standard.mdmConfiguration = configuration     //  bindedValue.toggle()     }   }   private var cancelable: AnyCancellable?   init() {  // init(toggle: Binding<Bool>) {     //_bindedValue = toggle     cancelable = UserDefaults.standard.publisher(for: \.mdmConfiguration)       .sink(receiveValue: { [weak self] newValue in         guard let self = self else { return }         if newValue != self.configuration { // avoid cycling !!           self.configuration = newValue         }       })   } } struct ContentView: View {       @State private var isConfigurationAvailable: Bool = false   @State private var showLoadingIndicator: Bool = true   @ObservedObject var configuration = MDMConfiguration()       var body: some View {           GeometryReader { geometry in               let width = geometry.size.width       let height = geometry.size.height                             VStack {         Text("CONTENT -> \(configuration.configuration.debugDescription)").padding()         Spacer()         if !configuration.configuration.isEmpty {           Text("AVAILABLE").padding()         } else {           Text("NIL NULL ZERO EMPTY")             .padding()         }       }        }   } } But it still doesn't ensure any changes in view, when I manually click on f.e. button, which prints the configuration in the console when it has uploaded, it does it well. Please help, my headache is reaching the zenith. I am a newbie in Swift development, maybe I did something weird and stupid. I hope so :D Thank in advance!
Replies
0
Boosts
0
Views
1.6k
Activity
Mar ’22
Swift 5.5 Concurrency: how to serialize async Tasks to replace an OperationQueue with maxConcurrentOperationCount = 1?
I’m currently migrating my app to use the concurrency model in Swift. I want to serialize Tasks to make sure they are executed one after the other (no paralellism). In my use case, I want to listen to notifications posted by the NotificationCenter and execute a Task every time a new notification is posted. But I want to make sure no previous task is running. It's the equivalent of using an OperationQueue with maxConcurrentOperationCount = 1. For example, I’m using CloudKit with Core Data in my app and I use persistent history tracking to determine what changes have occurred in the store. In this Synchronizing a Local Store to the Cloud Sample Code, Apple uses an operation queue for handling history processing tasks (in CoreDataStack). This OperationQueue has a maximum number of operations set to 1. private lazy var historyQueue: OperationQueue = { let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 return queue }() When a Core Data notification is received, a new task is added to this serial operation queue. So if many notifications are received, they will all be performed one after the other one in a serial way. @objc func storeRemoteChange(_ notification: Notification) { // Process persistent history to merge changes from other coordinators. historyQueue.addOperation { self.processPersistentHistory() } } In this Loading and Displaying a Large Data Feed Sample Code, Apple uses Tasks to handle history changes (in QuakesProvider). // Observe Core Data remote change notifications on the queue where the changes were made. notificationToken = NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: nil, queue: nil) { note in Task { await self.fetchPersistentHistory() } } I feel something is wrong in the second project as Tasks could happen in any order, and not necessarily in a serial order (contrary to the first project where the OperationQueue as a maxConcurrentOperationCount = 1). Should we use an actor somewhere to make sure the methods are serially called? I thought about an implementation like this but I’m not yet really comfortable with that: actor PersistenceStoreListener { let historyTokenManager: PersistenceHistoryTokenManager = .init() private let persistentContainer: NSPersistentContainer init(persistentContainer: NSPersistentContainer) { self.persistentContainer = persistentContainer } func processRemoteStoreChange() async { print("\(#function) called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") } } where the processRemoteStoreChange method would be called by when a new notification is received (AsyncSequence): notificationListenerTask = Task { let notifications = NotificationCenter.default.notifications(named: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator) for await _ in notifications { print("notificationListenerTask called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") await self.storeListener?.processRemoteStoreChange() } }
Replies
1
Boosts
0
Views
5.9k
Activity
Mar ’22
Using actors in a SwiftUI .task
Hi, having the concurrency checks (-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks) enabled I always get this warning, when trying to access/use an actor in a SwiftUI .task: "Cannot use parameter 'self' with a non-sendable type 'ContentView' from concurrently-executed code". What would be a correct implementation? Here's a minimal code-sample which produces this warning: import SwiftUI struct ContentView: View { @State var someVar = 5 var a1 = A1() var body: some View { Text("Hello, world!") .padding() .task { await a1.doSomething() } } } public actor A1 { func doSomething() { print("Hello") } }
Replies
1
Boosts
0
Views
2.4k
Activity
Feb ’22
@MainActor and the guarantee that the properties are only ever accessed from the main actor
In https://developer.apple.com/videos/play/wwdc2021-10019/?time=815 was said: "By adding the new @MainActor annotation to Photos, the compiler will guarantee that the properties (...) are only ever accessed from the main actor." What does it exactly mean? Let's consider the following example: @MainActor class ViewModel: ObservableObject {   @Published var text = "" } struct ContentView: View {   @StateObject private var viewModel = ViewModel()   var body: some View {     VStack {       Text(viewModel.text)         .padding()       Button("Refresh") {         Task.detached {           await updateText()         }       }     }   }   func updateText() async {     viewModel.text = "Hello, world"   } } Compiler doesn't complain. After button tap viewModel.text is changed from background actor and there is runtime warning: "Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates." So once again: How exactly @MainActor annotation and the compiler will guarantee that the properties are only ever accessed from the main actor?
Replies
0
Boosts
0
Views
1.4k
Activity
Jan ’22
Manipulating SwiftUI view state in a Task closure (button action)
In the session Discover concurrency in SwiftUI (at 19:48), the following sample code is presented as an example of starting an async task from a Button action (which is synchronous): struct SavePhotoButton: View { var photo: SpacePhoto @State private var isSaving = false var body: some View { Button { Task { isSaving = true await photo.save() isSaving = false } } label: { Text("Save") // … } // … } } (The code on the slide uses async { … }. I replaced this with the current Task { … } syntax.) I'm wondering if manipulating view state from inside the task closure like this is allowed. In fact, when you compile this with -Xfrontend -warn-concurrency, you get compiler warnings on all three lines in the task closure: Task { // warning: Cannot use parameter 'self' with a non-sendable type 'SavePhotoButton' from concurrently-executed code isSaving = true // same warning await photo.save() // same warning isSaving = false } You have to mark the view as @MainActor to get rid of the warnings: @MainActor struct SavePhotoButton: View { … } Questions: Can you confirm that the sample code is invalid without the @MainActor annotation on the view? How does the Task { … } closure guarantees that it runs on the main actor. I know that Task { … } inherits the current actor execution context, but how does that work here? My guess: View.body is annotated with @MainActor in the SwiftUI module interface Actor context inheritance is based on the lexical scope, so the fact that the Task { … } closure is inside body is enough for it to inherit that context, even if it's called from another context. Is this correct? Thanks.
Replies
0
Boosts
0
Views
2.2k
Activity
Nov ’21
Hide the View when in use navigationBarItems
When I tap to move to another screen and go back to the previous screen the View on navigationBarItems is partially obscured Hope can you help me !... Thanks
Replies
1
Boosts
0
Views
803
Activity
Aug ’21
Initialize app with an Async function | SwiftUI
I need my app to configure the backend at start, here's the function to do so: // Initializes Amplify final func configureAmplify() async { do { // Amplify.Logging.logLevel = .info let dataStore = AWSDataStorePlugin(modelRegistration: AmplifyModels()) let syncWithCloud = AWSAPIPlugin() let userAuth = AWSCognitoAuthPlugin() try Amplify.add(plugin: userAuth) try Amplify.add(plugin: dataStore) try Amplify.add(plugin: syncWithCloud) try Amplify.configure() print("Amplify initialized") } catch { print("Failed to initialize Amplify with \(error)") } } I tried placing it in the @main init like so: init() async { await networkController.configureAmplify() } but I get the following error: Type 'MyApplicationNameApp' does not conform to protocol 'App' I try to apply the suggestions after that which is to initialize it: init() { } but it seems odd, so now I have 2 init. What is going on here and what is the correct way to initialize multiple async functions at the start of the app, example: Code above (configure amplify) Check if user is logged in Set session etc Note: The init() async never gets called in the example above which is another problem within this question, so what is the correct way to initialize async function when the app starts.
Replies
1
Boosts
0
Views
4.3k
Activity
Aug ’21
Line Application Crash when Video Call Started
How can I fix this crash. This happens every time the Video call in the Line Chat application start.
Replies
0
Boosts
0
Views
470
Activity
Jul ’21
Deduplication of Tasks
A pretty common piece of work I'd like to generalize a Task version of is deduplicating work in callback logic by stashing the equivalent callbacks to be called when the shared underlying work is done. I have a fairly naive version of this working as it's own Task/actor/async/await soup import Foundation public actor Dupes<Key: Hashable, Success, Failure: Error> {     private var tasks = [Key:Task<Success, Failure>]() } public extension Dupes where Failure == Error {     func async(key: Key, priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success) async throws -> Success {         if let task = tasks[key] {             return try await task.value         } else {             let task = Task(priority: priority) {                 try await operation()             }             tasks[key] = task             let data = try await task.value             tasks.removeValue(forKey: key)             return data         }     } } public extension Dupes where Failure == Never {     func async(key: Key, priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Success) async -> Success {         if let task = tasks[key] {             return await task.value         } else {             let task = Task(priority: priority) {                 await operation()             }             tasks[key] = task             let data = await task.value             tasks.removeValue(forKey: key)             return data         }     } } That can used like so if we had an async method that returns a value (bar()) based on some work that we know is shared based on the identifier 123 let foo = Foo() let dupes = Dupes<String, Int, Never>() Task.detached { await dupes.async(key: "123") {     await foo.bar() } } Task.detached { await dupes.async(key: "123") {     await foo.bar() } } In naive testing this seems to work. It feels really odd to be handing off to another actor for managing state that seems internal to whatever actor would need to avoid duplicate work. I tried defining similar methods on a custom actor or on an extension on Actor but passing the storage via keyPath or inout violates the mutability rules of actors (which to be fair makes sense). Is there an idiom for this kind of book keeping? A good real world example of this is network requests where I'd pass in a Hashable network request that makes or owns a URLRequest for me to hand off to URLSession. I don't want to download the same request twice and I don't want to write the same book keeping logic again and again.
Replies
0
Boosts
0
Views
912
Activity
Jul ’21