I made a test with a new XIB-based project using this code
func applicationDidFinishLaunching(_ aNotification: Notification) {
guard let content = window.contentView else {
print("Error: cannot access windows contentview!")
return
}
let tv = NSTextView(frame: NSMakeRect(100, 300, 200, 40))
tv.string = "Text subview"
tv.font = NSFont.systemFont(ofSize: 30.0)
content.addSubview(tv)
let chartView = NSHostingView(rootView: myChart())
chartView.setFrameSize(content.frame.size)
content.addSubview(chartView)
content.printView(self)
}
"myChart" is s sample view using Charts.
The window does show the text and the chart but the print shows the text only.
How can I get the SwiftUI-View printed?
My goal is a PDF output of a SwiftUI view.
There are already several older threads with similar questions but no solution, yet.
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Post
Replies
Boosts
Views
Activity
I've seen several posts regarding NavigationStack in a NavigationSplitView. All had specific issues and some were marked as resolved. I couldn't get any of the suggested solutions working on macOS so I'll present some stripped down examples, all part of FB11842563:
1. Sidebar Selection
struct SidebarSelection: View {
@State var selection: Int?
@State var path: [Int] = []
var body: some View {
NavigationSplitView {
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
} detail: {
NavigationStack(path: $path) {
VStack {
Image(systemName: "x.squareroot")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("This is the NavigationStack root")
}
.padding()
.navigationDestination(for: Int.self) { number in
Text("You chose \(number)")
}
}
}
.onChange(of: selection) { newValue in
print("You clicked \(newValue)")
if let newValue {
path.append(newValue)
}
}
.onChange(of: path) { newValue in
print("Path changed to \(path)")
}
}
}
If we run this and click:
„I like 5“
„I like 6“
„I like 7“
We would expect the detail view to show:
„You chose 5“
„You chose 6“
„You chose 7“
And the console to show:
You clicked Optional(5)
Path changed to [5]
You clicked Optional(6)
Path changed to [5, 6]
You clicked Optional(7)
Path changed to [5, 6, 7]
What we actually see in the detail view is:
„You chose 5“
„This is the NavigationStack root“
„You chose 7“
And the console shows:
Update NavigationRequestObserver tried to update multiple times per frame.
You clicked Optional(5)
Path changed to [5]
You clicked Optional(6)
Path changed to []
You clicked Optional(7)
Path changed to [7]
2. Sidebar and Stack Selection
Now we copy the list to the navigationDestination:
struct SidebarAndStackSelection: View {
@State var selection: Int?
@State var path: [Int] = []
var body: some View {
NavigationSplitView {
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
} detail: {
NavigationStack(path: $path) {
VStack {
Image(systemName: "x.squareroot")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("This is the NavigationStack root")
}
.padding()
.navigationDestination(for: Int.self) { number in
VStack {
Text("You chose \(number)")
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
}
}
}
}
.onChange(of: selection) { newValue in
print("You clicked \(newValue)")
if let newValue {
path.append(newValue)
}
}
.onChange(of: path) { newValue in
print("Path changed to \(path)")
}
}
}
We repeat our test from above, clicking either on the sidebar or in the detail view and we expect the same outcome. This time the detail view shows the expected screen and the path is not completely wiped out but it is also not appended:
Update NavigationRequestObserver tried to update multiple times per frame.
You clicked Optional(5)
Path changed to [5]
You clicked Optional(6)
Path changed to [6]
You clicked Optional(7)
Path changed to [7]
3. Sidebar and Stack Selection, initialized
Same as before, but now we initialize the view with a non-empty path:
SidebarAndStackSelection(path: [1])
The app freezes on launch, CPU is at 100 percent and the console shows only:
Update NavigationRequestObserver tried to update multiple times per frame.
Update NavigationRequestObserver tried to update multiple times per frame.
The SwiftUI instruments seem to show heavy activity of the Stack and the SplitView:
4. Selection only in Stack
Once we remove the selection from the sidebar everything works as expected (adding the NavigationStack to the root view to be able to click on a number):
struct SidebarWithoutSelectionButStack: View {
@State var selection: Int?
@State var path: [Int] = []
var body: some View {
NavigationSplitView {
List(1...20, id: \.self) { number in
Text("I like \(number)")
}
} detail: {
NavigationStack(path: $path) {
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
.padding()
.navigationDestination(for: Int.self) { number in
VStack {
Text("You chose \(number)")
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
}
}
}
}
.onChange(of: selection) { newValue in
print("You clicked \(newValue)")
if let newValue {
path.append(newValue)
}
}
.onChange(of: path) { newValue in
print("Path changed to \(path)")
}
}
}
Problem of course is, that now the sidebar is useless.
I added a keyboard toolbar inside ZStack. And it works right after appears as expected
But after opening and closing another view over the .sheet modifier, The keyboard toolbar doesn't show anymore.
ZStack { . .. TextField() .toolbar { ToolbarItemGroup(placement: .keyboard) { .... } } } .sheet(isPresent: $binding) { Some other view }
Seems it happened after upgrading to iOS 16. Does anybody has the solution?
Thanks
I have added additional localizations into my iOS app. iOS is not available in those languages. So I did as it is suggested that you redirect customers to app settings view UIApplication.openSettingsURLString and there they can select another app language.
Unfortunately they do not see language selection if they do not have set at least 2 Preferred languages in General -> Languages & Region. Also it does not matter what languages they have there. If my app does not support those then it still shows all localizations available.
Is there somehow to force it? So it would be visible always? Since most people in my country have iPhones only in English but would like to use Apps in their native language.. Since they do not have 2 preferred languages they cant see the selection :(
I have a SwiftUI View where the body looks like this
VStack {
VStack(spacing: 4) {
Text("Outline")
Button("Tap Me") {
print("tapped")
}
.buttonStyle(.outline)
}
VStack(spacing: 4) {
Text("Simple")
Button("Tap Me") {
print("tapped")
}
.buttonStyle(.simple)
}
}
So to remove the duplication, I want to do something like this:
func textButton(title: String, buttonStyle: ButtonStyle) -> some View {
VStack {
Text(title)
Button("hello") {
print("tapped")
}
.buttonStyle(buttonStyle)
}
}
The compiler asks me to add 'any' before ButtonStyle. When I do that I get the following:
"Type 'any View' cannot conform to 'View'"
It works fine if I don't pass in the ButtonStyle. Any suggestions on how to pass a ButtonStyle into a func?
thanks, in advance!
Generic parameter 'V' could not be inferred ERROR
Hello Apple Community,
With a backend development background, I was always reluctant to do any front end. Especially with my bad experience with html & css, my negative opinion towards UI only got stronger.
When starting a new project at my current company, I was forced to do SwiftUI for iOS. After a few small (I mean really small) hiccups, I really understood the concept and it all became natural.
This positive experience made me want to try other front end frameworks which work for web. I dipped my toes into Jetpack Compose, C# UWP/WPF, Rust with EGUI.
I was really impressed with the performance and possibilities of Rust (EGUI) compiled to WASM. I was especially impressed that you do not have to use any HTML or CSS rather the rendering is completely up to you just like with a desktop application. I was always disappointed of the necessity of html, but with the rise of WASM in the recent years, I really hope there will be amazing alternatives using WASM & WEBGL.
Rust with EGUI is good and all but lets be honest to our self: With the ease of SwiftUI, its obvious why all the best looking applications are on iOS.
Its time for SwiftUI in web.
The advantages for the developers are obvious:
Arguably better UI Framework
No Html DOM stuff
Friendlier for new developers
One framework & language for multiple platforms
etc ...
But whats in for Apple? Why "waste" resources?
In my opinion the most important thing is: Increased Developer adoption
What is your opinion on this topic?
Would you use SwiftUI for web?
What are you currently using for web?
Do you prefer any other frontend framework over SwiftUI? (not considering the platform)
Here are the sample codes:
import SwiftUI
struct Item: Identifiable, Hashable {
var id = UUID()
var text: String
}
struct Player: Identifiable {
var id = UUID()
var score: String
}
struct TestView: View {
@State var sidebarItems: [Item] = [
.init(text: "1"),
.init(text: "2")
]
@State var players: [Player] = [
.init(score: "2"),
.init(score: "3"),
.init(score: "6"),
.init(score: "1")]
@State private var selectedItem: Item?
var body: some View {
NavigationSplitView(columnVisibility: .constant(.all)) {
List(sidebarItems, selection: $selectedItem) { item in
Text(item.text)
}
Button("shuffle") {
withAnimation(.easeIn) {
players.shuffle()
sidebarItems.shuffle()
}
}
} content: {
List {
ForEach(players) { player in
Text(player.score)
}
}
} detail: {
Text("Detail")
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
But as a result. Animation working fine on content but not on sidebar
Hello,
we have weird crash in our app that mostly seems to happen right after launch. It is quite rare and so far I haven’t been able to reproduce it (the info below comes from Crashlytics).
The main error message I have is this:
failed to demangle witness for associated type 'Property' in conformance 'SwiftUI.StateObject<AppBlock.QuickBlockActivityViewModel>.(unknown context at $18f34e5b8).Box: DynamicPropertyBox' from mangled name ' � ��yxG' - subject type x does not conform to protocol ObservableObject
And here is the stack trace:
Crashed: com.apple.main-thread
0 libsystem_kernel.dylib 0x7200 __pthread_kill + 8
1 libsystem_pthread.dylib 0x71ac pthread_kill + 268
2 libsystem_c.dylib 0x20ca0 abort + 180
3 libswiftCore.dylib 0x3d7304 swift::fatalError(unsigned int, char const*, ...) + 134
4 libswiftCore.dylib 0x3d7324 swift::warningv(unsigned int, char const*, char*) + 30
5 libswiftCore.dylib 0x3ee678 swift_getAssociatedConformanceWitnessSlowImpl(swift::TargetWitnessTable<swift::InProcess>*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::InProcess> const*) + 2078
6 libswiftCore.dylib 0x3ecb9c swift_getAssociatedTypeWitness + 236
7 SwiftUI 0x5b838 OUTLINED_FUNCTION_49 + 640
8 SwiftUI 0xa8d68 OUTLINED_FUNCTION_513 + 16260
9 SwiftUI 0x58244 OUTLINED_FUNCTION_177 + 10892
10 SwiftUI 0x95524 OUTLINED_FUNCTION_1160 + 6632
We are using the view model (QuickBlockActivityViewModel) in a SwiftUI view that is part of collection view using the new UIHostingConfiguration from iOS 16.
Our view model is a subclass of view model for older iOS versions that conforms to ObservableObject and is marked as @MainActor.
And the view model is used like this:
@StateObject private var viewModel = QuickBlockActivityViewModel()
Internally the view model uses Combine to monitor a couple of states from other parts of the app to modify its properties.
I developed an app with 10 widgets but some iPhone, iPad or macOS
users report that my widgets or the "App Name" don't appear in the
widgets list when they tried to add the widgets of my app.
There's no way I can replicate the problem, but the number of the users that report this issue is growing up every day.
It’s not clear if the problem is caused by the iPhone model, a crash on the widget preview or other factors.
My widgets previews are built reading static data, so this data is the same in every conditions.
I suggest my users to do the following steps:
Start the app and go to check again if "App name" appears among widget List
Close every app and restart the device; then start the app and
go to check again if "App name" appears among widget List
Temporarily change system language and turn on Bold Text and go to check again if "App Name" appears among widget List
Uninstall and reinstall the app, start the app and go to check again if "App Name" appears among widget List
But all users who have tried these steps say that the app still does not appear in the list of widgets.
The following code is the one I use inside the main widgets swift file called TodayWidgetExtension:
import WidgetKit
import SwiftUI
struct PlaceholderView : View {
var body: some View {
Text("loading")
}
}
//MARK: - Main widget bundle configuration
@main
struct WidgetBundle: WidgetBundle {
@WidgetBundleBuilder
var body: some Widget {
//MARK: - 1
Widget1Large()
Widget1Medium()
Widget1Small()
if #available(iOSApplicationExtension 16.0, *) {
Widget1Accessory()
}
//MARK: - 2
Widget2Large()
//MARK: - 3
#if !targetEnvironment(macCatalyst)
Widget3Medium()
#endif
//MARK: - 4
Widget4Large()
//MARK: - 5
Widget5Medium()
//MARK: - 6
Widget6Large()
Widget6Medium()
}
}
struct todaywidgetextension_Previews: PreviewProvider {
static var previews: some View {
PlaceholderView()
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
The only thing that I've noticed debugging the widgets extension is
that, even if I don't add any of them to my iPhone screen, Xcode tells
me that widgets occupied 20mb of memory (the limit for widgets is 30mb).
I tried removing all the widgets from the above code leaving only one
(Widget1Small for example), but Xcode continues to tell me that 20mb of
memory are still occupied.
I hope that someone can help me.
Thank you.
I'm implementing a Timer in my app and I want the countdown to show up as a Live Activity. It works, but I get a very weird expanding effect on the Text view. The screenshots below show the issue, I can't tell if it's a bug or if I'm doing something wrong.
My goal is to shrink the live activity black area so that it's a smaller, more reasonable size. There's no reason for it to be as large as it is on the trailing side.
The Live Activity code (very basic):
} dynamicIsland: { context in
} compactTrailing: {
// Important bit is here
Text(Date(), style: .timer)
}
}
Which renders like this, with a lot of space after the timer:
Adding a background color shows the view is expanding:
Text(Date(), style: .timer)
.background(.red)
And if I replace the timer with a standard text view, then no issue:
Text("Hello")
.background(.red)
Getting out of live activities and showing a standard timer view, there is no expansion issue:
struct TestView: View {
var body: some View {
Text(Date(), style: .timer)
.background(.red)
}
}
So... I'm stumped. Any advice is appreciated.
i saw there is a way to track hands with vision, but is there also a way to record that movement and export it to fbx? Oh and is there a way to set only one hand to be recorded or both at the same time? Implementation will be in SwiftUI
Problem
LongPressGesture ignores minimumDuration parameter and succeeds immediately, also onEnded is never invoked.
Steps to reproduce
Take Apple’s own sample code from their documentation: LongPressGesture.
Remove transaction.animation = Animation.easeIn(duration: 2.0) line to make the effect more obvious.
Expected result:
The circle must turn red after 3 seconds of pressing on it, and turn green when released.
Actual result
The circle turns red immediately and never turns green.
Notes
I tried many combinations of .gesture and .simultaneousGesture applied to different types of views. Was anyone able to make the minimum duration work when passed to .gesture modifier?
Hello,
I have made a picker that is filled with data from an API endpoint. The data is retrieved and shown properly, however, when trying to change the selection on the picker, it does not work.
For simple demonstration i have put the picker in a empty view. Here is the code:
import SwiftUI
struct TestView: View {
struct Subject: Hashable {
let subjectId: Int
let subjectName: String
}
@State var subjects: [Subject] = []
@State var selectedSubject: Subject? = nil
var body: some View {
VStack {
Picker(selection: $selectedSubject, label: Text("Kies een vak")) {
ForEach(subjects, id: \.self) { subject in
Text(subject.subjectName).tag(subject)
}
}
.frame(width: 300, height: 50)
.background(Color.black.opacity(0.05))
.cornerRadius(10)
.onChange(of: selectedSubject) { newSubject in
print("Chosen subject: \(newSubject?.subjectId ?? -1)")
}
Text("Chosen subject: \(selectedSubject?.subjectId ?? -1)")
}
.onAppear {
Api().extractSubjects { subjects in
DispatchQueue.main.async {
self.subjects = subjects.map { TestView.Subject(subjectId: $0.subjectId, subjectName: $0.subjectName) }
}
}
}
}
}
To better illustrate what I mean i have made a screenrecording:
I hope you guys and girls can help me out. If you need more info, please let me know!
Any help or suggestion is greatly appreciated, thanks!
I'm building a macOS app using SwiftUI and I recently updated to xcode 14.3. Since then I've been debugging why none of my animations were working, it turned out that the NavigationSplitView or NavigationStack are somehow interfering with all the animations from withAnimation to .transition() and everything in between.
Is anyone else experiencing this, knows a work around or knows why this is happening?
After implementation of deep linking and when we click link in notes or email then it should call
.onContinueUserActivity in Swiftui.
But it's not happening.
Can someone help me, how to do it.
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?
Can someone please shed some light? I have an app that uses Core Data and CloudKit, up until the last version, I was able to sync data between devices but now after I added two new Entities for some reason it stopped syncing between devices.
Here is how I did the change:
Created a new Core Data container.
Added the new Entities and their Attributes
Tested the new Entities locally to be able to send the new schema to CloudKit.
Went to CloudKit and made sure that the new Entities and Attributes were reflected on the Developent database.
Deploy Schema Cahnges.
Went to the Production database to make sure the new schema was deployed; and it was, both databases look the same.
Testing:
Tested in the simulator and with a real device and everything syncs, even the new Entities.
If I download the app from the App Store on two different devices they do NOT sync.
Based on the procedure I'm describing above, is there any important step I may have missed when doing the migration?
I'm not sure if this is related to the syncing issue but after testing a few times, I no longer can turn the iCloud on, I get the following message when I try to turn iCloud Sync On.
CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate resetAfterError:andKeepContainer:]: <NSCloudKitMirroringDelegate: 0x282c488c0> - resetting internal state after error: Error Domain=NSCocoaErrorDomain Code=134410 "CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process." UserInfo={NSURL=file:///var/mobile/Containers/Data/Application/73F19BC7-4538-4098-85C7-484B36192CF3/Library/Application%20Support/CoreDataContainer.sqlite, NSLocalizedFailureReason=CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process., NSUnderlyingException=Illegal attempt to register a second handler for activity identifier com.apple.coredata.cloudkit.activity.setup.8D4C04F6-8040-445A-9447-E5646484521}
Any idea of what could be wrong and preventing the devices from syncing? Any idea or suggestion is welcome.
Thanks
I have a view which shows some data based on a complex calculation. Let's say I need to parse some input string and transform it in some way.
private func someComplexCalculation(_ input: String) -> String {
// ...
}
The most naive approach would be to perform this in the view's body:
struct MyView: View {
let input: String
var body: some View {
Text(someComplexCalculation(input))
}
}
But of course, we want to keep body nice and fast because SwiftUI may call it very often. The text to be displayed will be constant for a particular view, in a particular place in the hierarchy (barring some major events such as locale changes, which can basically change the entire UI anyway).
So the next idea would be to hoist the calculation out of body in to the view's initialiser:
struct MyView: View {
let value: String
init(_ value: String) {
self.value = someComplexCalculation(value)
}
var body: some View {
Text(value)
}
}
Except that this view's initialiser will be called in the body of its parent, so this isn't really much of a win at all.
So the next idea is that we need to associate the cached data with the underlying view itself somehow. From what we are told about SwiftUI, that's what @State does.
struct MyView: View {
@State var value: String
init(_ value: String) {
self._value = State(initialValue: someComplexCalculation(value))
}
var body: some View {
Text(value)
}
}
Except... apparently this is not recommended because SwiftUI won't honour the value set in the initialiser.
That's kind of okay for my purposes - the contents won't change, and every view with the same identity (place in the hierarchy) will be provided the same input. The real problem emerges when we look at the documentation for @State. Its initialiser takes a value directly, so we're still going to perform this expensive calculation every time; we'll just discard the value immediately afterwards and take one which the framework memoised.
Which brings me on to my final approach - @StateObject. Unlike @State, its initialiser takes an autoclosure, so we won't recompute the value every time. But it should still be stored in a way that is bound to the underlying view, thereby giving me a place to stash memoised values.
struct MyView: View {
final class Cache {
var transformed: String
init(input: String) {
self.transformed = someComplexCalculation(value)
}
}
@StateObject var cache: Cache
init(_ value: String) {
self._cache = StateObject(wrappedValue: Cache(input: value))
}
var body: some View {
Text(cache.transformed)
}
}
I haven't been able to find much in the way of others online using @StateObject for this purpose, so I'd like to ask - is there some other solution I'm overlooking? Is this considered a misuse of @StateObject for some reason? The documentation for the StateObject initialiser says:
Initialize using external data
If the initial state of a state object depends on external data, you can call this initializer directly. However, use caution when doing this, because SwiftUI only initializes the object once during the lifetime of the view — even if you call the state object initializer more than once — which might result in unexpected behavior.
Which seems fine. This seems like exactly what I want.
I have a performance issue with a Mac SwiftUI app. Using instruments I see hangs reported. When I zero in on a hang I see that the time profiler reports most of the hang -- in one example 658 out of 687 ms -- being in 'static AppName.$main() [inlined]'.
I think that is saying my app is busy, but busy doing what?
The "hangs" are related to SwiftUI table processing. User experience is something like this: select an item, see the view changes based upon selection show up a second or two later. The duration of the hang increases with the number of items in the table. I'm testing with 100 ~ 1200 table entries.