Below is my sample code. On the Home page, when I click "show sheet," the sheet page expands, and the StateObject inside the sheet is initialized once. However, when I click "show Fullscreen" and then click "show sheet" inside the fullscreen page, the sheet gets initialized twice.
However, if I remove navigationDestination, this issue does not occur.
This problem causes the network request in the sheet page to be triggered multiple times.
Can someone tell me the reason?
enum TestRouter: String, Hashable {
case test
var targetView: some View {
Text("test")
}
var title: String {
return "test title"
}
}
@MainActor
struct NavigationInnerView<Content>: View where Content: View {
var contentView: () -> Content
@MainActor public init(@ViewBuilder contentView: @escaping () -> Content) {
self.contentView = contentView
}
var body: some View {
NavigationStack() {
contentView()
.navigationDestination(for: TestRouter.self) { route in
route.targetView
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct ContentView: View {
@State var showFullScreen: Bool = false
@State var showSheet: Bool = false
var contentView: some View {
VStack {
VStack {
Text("Home")
Button {
showFullScreen = true
} label: {
Text("show fullscreen")
}
Button {
showSheet = true
} label: {
Text("show sheet ")
}
}
}
}
var body: some View {
NavigationInnerView {
contentView
.fullScreenCover(isPresented: $showFullScreen) {
NavigationInnerView {
FullScreenContentView()
}
}
.sheet(isPresented: $showSheet) {
NavigationInnerView {
SheetContentView()
}
}
}
}
}
class FullScreenViewModel: ObservableObject {
@Published var content: Bool = false
init() {
print("Full Screen ViewModel init")
}
}
struct FullScreenContentView: View {
@Environment(\.dismiss) var dismiss
@State var showSheet: Bool = false
@StateObject var viewModel: FullScreenViewModel = .init()
init() {
print("Full screen view init")
}
var body: some View {
VStack {
Text("FullScreen")
Button {
dismiss()
}label: {
Text("dismiss")
}
Button {
showSheet = true
} label: {
Text("show sheet")
}
}
.sheet(isPresented: $showSheet) {
NavigationInnerView {
SheetContentView()
}
}
}
}
class SheetViewModel: ObservableObject {
@Published var content: Bool = false
init() {
print("SheetViewModel init")
}
}
struct SheetContentView: View {
@Environment(\.dismiss) var dismiss
@StateObject var viewModel = SheetViewModel()
init() {
print("sheet view init")
}
var body: some View {
Text("Sheet")
Button {
dismiss()
} label: {
Text("dismiss")
}
}
}
#Preview {
ContentView()
}
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I'm developing a grid of focusable elements in SwiftUI with different sizes for tvOS (similar to a tv channel grid).
Because the Focus Engine calculates the next view to focus based on the center of the currently focused view, sometimes it changes focus to an unexpected view. Here's an example:
Actual:
Expected:
Is it possible to customize the anchor point from which the focus engine traces a ray to the next view? I would prefer the leading edge in my case.
Hello!
I have a destination navigation which is TabVIew where each tab item is ScrollView. And when scrolling content of any of tab items is underneath navigation bar its background is always hidden. But at the same time tab bar background is toggled depending on scrolling content position.
I expected it would work with TabView the same as with any other view.
Is it supposed to work like that?
I have a view that lets the user position and size a bunch of subviews. I use .frame() and .position() to accomplish this.
Right now, if the user resizes the window, the views stay where they are, anchored to the top-left corner. What I'd like is for the views to scale as a whole with window, maintaining their relative position, and their aspect ratios.
I can apply .scaleEffect(_:anchor:) to the containing view, and it scales them the way I want, but I'm not sure how to tie it to the window.
My first thought is to use a GeometryReader, but I don't really know what the "original" size would have been in order to compute a scale factor.
How else might I accomplish this?
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hello!
I’m experiencing a crash in my iOS/iPadOS app related to a CALayer rendering process. The crash occurs when attempting to render a UIImage on a background thread. The crashes are occurring in our production app, and while we can monitor them through Crashlytics, we are unable to reproduce the issue in our development environment.
Relevant Code
I have a custom view controller that handles rendering CALayers onto images. This method creates a CALayer on the main thread and then starts a detached task to render this CALayer into a UIImage. The whole idea is learnt from this StackOverflow post: https://stackoverflow.com/a/77834613/9202699
Here are key parts of my implementation:
class MyViewController: UIViewController {
@MainActor
func renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) async -> UIImage? {
// Create CALayer and add it to the view.
CATransaction.begin()
let customLayer = MyDrawingLayer()
customLayer.setupContent(itemsToDraw: itemsToDraw)
// Position the frame off-screen to it hidden.
customLayer.frame = CGRect(
origin: CGPoint(x: -100 - size.width, y: -100 - size.height),
size: size)
customLayer.masksToBounds = true
customLayer.drawsAsynchronously = true
view.layer.addSublayer(customLayer)
CATransaction.commit()
// Render CALayer to UIImage in background thread.
let image = await Task.detached {
customLayer.setNeedsDisplay()
let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { // CRASH happens on this line
let cgContext = $0.cgContext
cgContext.saveGState()
cgContext.concatenate(transform)
customLayer.render(in: cgContext)
cgContext.restoreGState()
}
return image
}.value
// Remove the CALayer from the view.
CATransaction.begin()
customLayer.removeFromSuperlayer()
CATransaction.commit()
return image
}
}
class MyDrawingLayer: CALayer {
var itemsToDraw: [MyDrawingItem] = []
func setupContent(itemsToDraw: [MyDrawingItem]) {
self.itemsToDraw = itemsToDraw
}
override func draw(in ctx: CGContext) {
for item in itemsToDraw {
// Render the item to the context (example pseudo-code).
// All items are thread-safe to use.
// Things to draw may include CGPath, CGImages, UIImages, NSAttributedString, etc.
item.draw(in: ctx)
}
}
}
Crash Log
The crash occurs at the following location:
Crashed: com.apple.root.default-qos.cooperative
0 MyApp 0x5cb300 closure #1 in closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 4313002752 (<compiler-generated>:4313002752)
1 MyApp 0x5cb300 closure #1 in closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 4313002752 (<compiler-generated>:4313002752)
2 MyApp 0x1a4578 AnyModifier.modified(for:) + 4308649336 (<compiler-generated>:4308649336)
3 MyApp 0x7b4e64 thunk for @escaping @callee_guaranteed (@guaranteed UIGraphicsPDFRendererContext) -> () + 4315008612 (<compiler-generated>:4315008612)
4 UIKitCore 0x1489c0 -[UIGraphicsRenderer runDrawingActions:completionActions:format:error:] + 324
5 UIKitCore 0x14884c -[UIGraphicsRenderer runDrawingActions:completionActions:error:] + 92
6 UIKitCore 0x148778 -[UIGraphicsImageRenderer imageWithActions:] + 184
7 MyApp 0x5cb1c0 closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 100 (FileName.swift:100)
8 libswift_Concurrency.dylib 0x60f5c swift::runJobInEstablishedExecutorContext(swift::Job*) + 252
9 libswift_Concurrency.dylib 0x62514 swift_job_runImpl(swift::Job*, swift::SerialExecutorRef) + 144
10 libdispatch.dylib 0x15ec0 _dispatch_root_queue_drain + 392
11 libdispatch.dylib 0x166c4 _dispatch_worker_thread2 + 156
12 libsystem_pthread.dylib 0x3644 _pthread_wqthread + 228
13 libsystem_pthread.dylib 0x1474 start_wqthread + 8
Questions
Is it safe to run UIGraphicsImageRenderer.image on the background thread?
Given that I want to leverage GPU rendering, what are some best practices for rendering images off the main thread while ensuring stability?
Are there alternatives to using UIGraphicsImageRenderer for background rendering that can still take advantage of GPU rendering?
It is particularly interesting that the crash logs indicate the error may be related to UIGraphicsPDFRendererContext (crash log line number 3). It would be very helpful if someone could explain the connection between starting and drawing on a UIGraphicsImageRenderer and UIGraphicsPDFRendererContext.
Any insights or guidance on this issue would be greatly appreciated. Thanks!!!
Could an Apple employee that works on SwiftUI please explain the update() func in the DynamicProperty protocol? The docs have ambiguous information, e.g.
"Updates the underlying value of the stored value."
and
"SwiftUI calls this function before rendering a view’s body to ensure the view has the most recent value."
From: https://developer.apple.com/documentation/swiftui/dynamicproperty/update()
How can it both set the underlying value and get the most recent value? What does underlying value mean? What does stored value mean?
E.g. Is the code below correct?
struct MyProperty: DynamicProperty {
var x = 0
mutating func update() {
// get x from external storage
x = storage.loadX()
}
}
Or should it be:
struct MyProperty: DynamicProperty {
let x: Int
init(x: Int) {
self.x = x
}
func update() {
// set x on external storage
storage.save(x: x)
}
}
This has always been a mystery to me because of the ambigious docs so thought it was time to post a question.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Let's say I want to build a simple photo management app on Mac or iPad with Swift UI. This app has multi-window support. My photos are organized inside albums. I should be able to drag photos between windows from one album to another.
I struggle to get this working properly with Swift UI. Writing modern code I would like to use Transferable. Let's say my photos are not real files. So I can't use a FileRepresentation. Instead I use CodableRepresentation and encode an identifier. This identifier is later used to drive the move operation between folders.
I ran into some limitations here
Transferable seems to be meant for copy-like Drag & Drop operations. I have no possible to get a "move" cursor on macOS (it's always the copy cursor with the green + sign). Also the API reads like it is about importing/exporting – not moving.
When using dropDestination on ForEach, I completely lack the possibility to deny a drop (e.g. when a photo is already part of the album).
I'd like to have modifier key to switch between copying and moving.
Sometimes a drop should be redirected to a different index. How to do that?
Is there any chance to do this with Transferable? It even doesn't seem to be easy with NSItemProvider and onDrop/onDrag? Or should we still use a plain old UICollectionView/NSCollectionView, if we want to have more sophisticated control over drag/drop validation?
Hi,
I see some apps like LinkedIn that doesn't support multi view or split views on iPad, but seems this feature is enabled by default to any new project in Xcode, how to disable it ?
Kind Regards
Topic:
UI Frameworks
SubTopic:
General
The SwiftUI Playground code below demonstrates that a .jpeg image can be read and written to the iOS file system. While, a.png image can only be read; the writing request appears to be ignored. Can anyone please tell me how to code to save a .png image using SwiftUI to the iOS file system.
Code:
import SwiftUI
import UniformTypeIdentifiers
/*
(Copied from Playground 'Help' menu popup.)
UIImage Summary
An object that manages image data in your app.
You use image objects to represent image data of all kinds, and the UIImage class is capable of managing data for all image formats supported by the underlying platform. Image objects are immutable, so you always create them from existing image data, such as an image file on disk or programmatically created image data. An image object may contain a single image or a sequence of images for use in an animation.
You can use image objects in several different ways:
Assign an image to a UIImageView object to display the image in your interface.
Use an image to customize system controls such as buttons, sliders, and segmented controls.
Draw an image directly into a view or other graphics context.
Pass an image to other APIs that might require image data.
Although image objects support all platform-native image formats, it’s recommended that you use PNG or JPEG files for most images in your app. Image objects are optimized for reading and displaying both formats, and those formats offer better performance than most other image formats. Because the PNG format is lossless, it’s especially recommended for the images you use in your app’s interface.
Declaration
class UIImage : NSObject
UIImage Class Reference
*/
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ImageFileDoc: FileDocument {
static var readableContentTypes = [UTType.jpeg, UTType.png]
static var writableContentTypes = [UTType.jpeg, UTType.png]
var someUIImage: UIImage = UIImage()
init(initialImage: UIImage = UIImage()) {
self.someUIImage = initialImage
}
init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents,
let some = UIImage(data: data)
else {
throw CocoaError(.fileReadCorruptFile)
}
self.someUIImage = some
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
switch configuration.contentType {
case UTType.png:
if let data = self.someUIImage.pngData() {
return .init(regularFileWithContents: data)
}
case UTType.jpeg:
if let data = self.someUIImage.jpegData(compressionQuality: 1.0) {
return .init(regularFileWithContents: data)
}
default:
break
}
throw CocoaError(.fileWriteUnknown)
}
}
struct ContentView: View {
@State private var showingExporterPNG = false
@State private var showingExporterJPG = false
@State private var showingImporter = false
@State var message = "Hello, World!"
@State var document: ImageFileDoc = ImageFileDoc()
@State var documentExtension = ""
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text(message)
Button("export") {
if documentExtension == "png" {
message += ", showingExporterPNG is true."
showingExporterPNG = true
}
if documentExtension == "jpeg" {
message += ", showingExporterJPG is true."
showingExporterJPG = true
}
}
.padding(20)
.border(.white, width: 2.0)
.disabled(documentExtension == "")
Button("import") {
showingImporter = true
}
.padding(20)
.border(.white, width: 2.0)
Image(uiImage: document.someUIImage)
.resizable()
.padding()
.frame(width: 300, height: 300)
}
// exporter .png
.fileExporter(isPresented: $showingExporterPNG, document: document, contentType: UTType.png) { result in
switch result {
case .success(let url):
message += ", .\(documentExtension) Saved to \(url.lastPathComponent)"
case .failure(let error):
message += ", Some error saving file: " + error.localizedDescription
}
}
// exporter .jpeg
.fileExporter(isPresented: $showingExporterJPG, document: document, contentType: UTType.jpeg) { result in
switch result {
case .success(let url):
message += ", .\(documentExtension) Saved to \(url.lastPathComponent)"
case .failure(let error):
message += ", Some error saving file: " + error.localizedDescription
}
}
// importer
.fileImporter(isPresented: $showingImporter, allowedContentTypes: [.png, .jpeg]) { result in
switch result {
case .failure(let error):
message += ", Some error reading file: " + error.localizedDescription
case .success(let url):
let gotAccess = url.startAccessingSecurityScopedResource()
if !gotAccess {
message += ", Unable to Access \(url.lastPathComponent)"
return
}
documentExtension = url.pathExtension
guard let fileContents = try? Data(contentsOf: url)
else {
message += ",\n\nUnable to read file: \(url.lastPathComponent)\n\n"
url.stopAccessingSecurityScopedResource()
return
}
url.stopAccessingSecurityScopedResource()
message += ", Read file: \(url.lastPathComponent)"
message += ", path extension is '\(documentExtension)'."
if let uiImage = UIImage(data: fileContents) {
self.document.someUIImage = uiImage
}else{
message += ", File Content is not an Image."
}
}
}
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
Files and Storage
Developer Tools
iPad
Swift Playground
Environment
Mac mini M4 Pro
macOS: Version 15.1.1 (24B2091)
Xcode: Version 16.1 (16B40)
IME: Kotoeri, Google IME
Code description
struct ContentView: View {
@State var text = “”
@State var selection: TextSelection?
var body: some View {
VStack {
TextEditor(text: $text, selection: $selection)
}
.padding()
}
}
Issue Description
When built for macOS (not Catalyst, Designed for iPad) and typing “あ” in Japanese input, it crashes.
I tried using Kotoeri's Kana input, Kotoeri's Roman input, and Google IME, but the same error occurs and crashes in both cases.
There is no issue when using English input.
Errors
(input method 56222 com.apple.inputmethod.Kotoeri.KanaTyping) (1): Fatal error: String index is out of bounds
(input method 56338 com.apple.inputmethod.Kotoeri.RomajiTyping (1): Fatal error: String index is out of bounds
Swift/StringUTF16View.swift:368: Fatal error: String index is out of bounds
Topic:
UI Frameworks
SubTopic:
SwiftUI
I have a simple SwiftUI Text:
Text(t) .font(Font.system(size: 9))
Strangely its ideal height seems to be larger when it is empty.
I initially observed this in a custom Layout container that wasn't working quite right. Eventually I looked at the height returned by v.dimensions(in:), and found that when t is non-empty the height is 11; when empty, it's 14.
Subsequently I observed similar behaviour in a regular VStack container.
Has anyone seen anything similar? Are there any properties that could affect this behaviour?
(This is on a watch - I don't know if that matters.)
Hi,
Despite having CarPlay capabilities authorised for our navigation app, our users are seeing some odd behaviour in the appearance of the icon in the sidebar menu on the side of the CarPlay display.
The documentation suggests the quickbar will show the most recently used: navigation app,
Open our app in CarPlay
Switch to another non-navigation app via CarPlay sidebar
Note that our navigation app remains in sidebar
Switch back to our navigation app
Search for destination, select, tap 'Let's Go' to start navigation
Switch to a non-navigation app via CarPlay sidebar
Note that our app is replaced by another navigation app in the sidebar (Google/Apple), despite being the most recently used
Any ideas?
Hello.
I have a scenario where a hover effect is being shown for a button that is disabled. Usually this doesn't happen but when you wrap the button in a Menu it doesn't work properly.
Here is some example code:
struct ContentView: View {
var body: some View {
NavigationStack {
Color.green
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Menu("Menu") {
Button("Disabled Button") {}
.disabled(true)
.hoverEffectDisabled() // This doesn't work.
Button("Enabled Button") {}
}
}
}
}
}
}
And here is what it looks like:
This looks like a SwiftUI bug. Any help is appreciated, thank you!
Hi,
I am having trouble setting default focus on a TextField that is inside of an alert. I expected TextField to receive default focus when alert is presented but result is that TextField does not receive default focus. This is happening on macOS 15.2, Swift (SwiftUI), Xcode 16.2 but hasn't worked on previous versions as well.
Example:
ContentView().alert("Sample Alert", isPresented: $present) {
AlertView()
} message: {
Text("Sample alert message.")
}
struct AlertView: View {
@Namespace private var namespace
@Environment(\.dismiss) private var dismiss
@State private var text = ""
var body: some View {
VStack {
TextField(text: $text, prompt: Text("Enter text")) {}
.onSubmit {
var _ = print(text)
dismiss()
}
.autocorrectionDisabled()
.lineLimit(1)
.prefersDefaultFocus(in: namespace)
Button("OK") {
dismiss()
}
Button("Cancel", role: .cancel) {
dismiss()
}
}
.focusScope(namespace)
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
In UIKit, it's quite common for table views to have one (or sometimes more) rows whose editing style is "insert", which show up a button with a plus symbol on a green background to the left of the cell content, and tapping this button adds whatever is in the cell content (usually a text field) to the list.
What's the procedure for creating a list row like this in Swift UI when in edit mode?
Topic:
UI Frameworks
SubTopic:
SwiftUI
I filed FB16332997 about the VERY high snowfall estimates I'm seeing in WeatherKit and iOS Weather. I initially thought something was wrong with my weather app but I verified the numbers with the iOS Weather app and another third party weather app.
For Atlanta last week it was saying 7.5" when it ended up being 2" (which I can live with).
Two days ago it reported there could be 16" of snow in northern Florida. That's impossible!
This morning it was reporting that Niceville could have 6-7" of snow, which would be significantly more than highest amount in recorded history for Florida (where snow is extremely rare).
It almost makes me wonder if the liquid precipitation value is actually the snowfall amount in reality. And then that is incorrectly being converted to the snowfall amount.
I have a use case in which there is a zoomable and pannable parent view, and a child view that needs to display a custom context menu on long press.
(The reason why I need to implement a custom context menu is this: https://developer.apple.com/forums/thread/773810)
It seems, however, that this setup produces a bug in SwiftUI. The problem is that the onChanged of the drag gesture is only invoked right before its onEnded, hence you cannot smoothly animate the drag:
struct ContentView: View {
var body: some View {
ZStack {
Rectangle()
.foregroundStyle(.green)
.frame(width: 200, height: 200)
.onLongPressGesture {
print("long press")
}
}
.gesture(MagnifyGesture().onEnded { value in
print("magnify end")
})
.gesture(DragGesture()
.onChanged { value in
print("drag change")
}
.onEnded { value in
print("drag end")
})
}
}
Changing the DragGesture to a .highPriorityGesture() makes the drag's onChange execute at the correct time but results in the LongPressGesture only triggering when the user lifts up his/her finger (which was originally not the case).
So it seems that the two gestures are in a sort of conflict with each other.
Is there a workaround?
Topic:
UI Frameworks
SubTopic:
SwiftUI
I am working on the EndPoint DLP solution project. So I want to monitor the paste operation peformed by the user. So when he uses the keyboard keys then I can monitor them using the event callback. But if user uses the GUI for pasting the data then how can I monitor that ?
Topic:
UI Frameworks
SubTopic:
General
I'm getting the following error Error Domain=com.google.GIDSignIn Code=-4. How do I find out what I'm missing with my setup of Google Cloud?
Topic:
UI Frameworks
SubTopic:
SwiftUI
According to the MVVM design pattern, one of my views depends on many properties in my model. Can I use logic like @published var model = MyModel()? Will there be a large performance loss? Will the UI be refreshed when other unrelated properties in the model are modified? What is the best practice in this case?
Topic:
UI Frameworks
SubTopic:
General