Post not yet marked as solved
How can I fix this crash. This happens
every time the Video call in the Line Chat application start.
Post not yet marked as solved
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.
Post not yet marked as solved
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
Post not yet marked as solved
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.
Post not yet marked as solved
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")
}
}
Post not yet marked as solved
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()
}
}
Post not yet marked as solved
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?
Post not yet marked as solved
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!
Post not yet marked as solved
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.
Post not yet marked as solved
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