Environment: macOS 11.0 beta 2, Xcode 12.0 beta 2.
I want to display a long Text inside a List with multiple lines without truncation. Here's my code:
import PlaygroundSupport
import SwiftUI
struct ContentView: View {
var body: some View {
List {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
}
}
}
let view = ContentView()
.frame(width: 250)
PlaygroundPage.current.setLiveView(view)
This code does the thing I want (multiline text) on iOS, but on macOS, the text is only a single line and truncated. You can paste this code into a playground to try it out.
If I replace the List with VStack, the text is rendered in multiple lines, so it seems List on macOS disables this behavior.
Here are a few modifiers I tried, but none achieves my desired result:
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
.lineLimit(nil)
.multilineTextAlignment(.leading)
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
.fixedSize(horizontal: false, vertical: true)
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
.frame(idealHeight: .infinity)
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
.frame(idealHeight: .greatestFiniteMagnitude)
Post
Replies
Boosts
Views
Activity
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.