Hi,
A class initialized as the initial value of an @State property is not released until the whole View disappears. Every subsequent instance deinitializes properly.
Am I missing something, or is this a known issue?
struct ContentView: View {
// 1 - init first SimpleClass instance
@State var simpleClass: SimpleClass? = SimpleClass(name: "First")
var body: some View {
VStack {
Text("Hello, world!")
}
.task {
try? await Task.sleep(for: .seconds(2))
// 2 - init second SimpleClass instance and set as new @State
// "First" should deinit
simpleClass = SimpleClass(name: "Second")
// 3 - "Second" deinit just fine
simpleClass = nil
}
}
}
class SimpleClass {
let name: String
init(name: String) {
print("init: \(name)")
self.name = name
}
deinit {
print("deinit: \(name)")
}
}
output:
init: First
init: Second
deinit: Second
Thanks
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
iOS 18.4.1
When I change a Google type event to an iCloud type, a "Cannot Save Event" prompt box pops up.
We have also received user feedback that recurring events also fail to save. After updating to iOS 18.4 when trying to save changes to an existing repeating event, the message "Cannot Save Event" will appear.
EventKitUI
Topic:
UI Frameworks
SubTopic:
UIKit
I have an app which uses Scene
var body: some Scene {
WindowGroup {
RootView(root: appDelegate.root)
.edgesIgnoringSafeArea(.all)
.onOpenURL { url in
let stringUrl = url.absoluteString
if (stringUrl.starts(with: "http")) {
handleUniversalLink(url: stringUrl)
} else if (stringUrl.starts(with: "fb")) {
let _ = ApplicationDelegate.shared.application(
UIApplication.shared,
open: url,
sourceApplication: nil,
annotation: [UIApplication.OpenURLOptionsKey.annotation])
}
}
}
}
I need to detect when a user taps on status bar. And call some functions when he does it. Is it possible in Swift?
Topic:
UI Frameworks
SubTopic:
SwiftUI
Let's say you have a protocol that can work with both classes and structs but you want to have a uniform UI to make edits.
What is the recommended way to have one view that will take both?
App
import SwiftUI
@main
struct ObservationTesterApp: App {
var body: some Scene {
WindowGroup {
ContentView(existence: Existence())
}
}
}
Types
import Foundation
protocol Dateable {
var timestamp:Date { get set }
}
struct Arrival:Dateable {
var timestamp:Date
}
@Observable
class Existence:Dateable {
var timestamp:Date
init(timestamp: Date) {
self.timestamp = timestamp
}
}
extension Existence {
convenience init() {
self.init(timestamp: Date())
}
}
ContentView, etc
//
// ContentView.swift
// ObservationTester
//
//
import SwiftUI
struct EditDateableView<TimedThing:Dateable>:View {
@Binding var timed:TimedThing
//note that this currently JUST a date picker
//but it's possible the protocol would have more
var body:some View {
DatePicker("Time To Change", selection: $timed.timestamp)
}
}
#Preview {
@Previewable @State var tt = Arrival(timestamp: Date())
EditDateableView<Arrival>(timed: $tt)
}
struct ContentView: View {
@State var arrival = Arrival(timestamp: Date())
@Bindable var existence:Existence
var body: some View {
//this work around also not allowed. "self is immutable"
// let existBinding = Binding<Existence>(get: { existence }, set: { existence = $0 })
VStack {
EditDateableView(timed: $arrival)
//a Binding cant take a Bindable
//EditDateableView<Existence>(timed: $existence)
}
.padding()
}
}
#Preview {
ContentView(existence: Existence())
}
This crash occurs when the app is started, and it is not necessary. The probability of occurrence is relatively low and it is not easy to reproduce. Please guide me how to deal with it. Thank you
Please see the crash log below
Crash log
I am working on creating a custom Popup View based on a .fullscreenCover. The .fullscreenCover is used to place the Popup content on screen on a semi-transparent background.
While this works on iOS 18, there is a problem on iOS 17: When the Popup content contains a .sheet, the background is not transparent any more but opaque.
Image: iOS 17. When showing the Popup an opaque background covers the main content. When tapping on the background it turns transparent.
Image: iOS 18. Everything works as intended. When showing the Popup the main background is covered with a semi-transparent background.
Removing the .sheet(...) from the Popup content solves the problem. It does not matter if the sheet is used or not. Adding it to the view code is enough to trigger the problem.
Using a .sheet within a .fullscreenCover should not be a problem as far as I know.
Is this a bug in iOS 17 or is there something wrong with my code?
Code:
struct SwiftUIView: View {
@State var isPresented: Bool = false
@State var sheetPresented: Bool = false
var body: some View {
ZStack {
VStack {
Color.red.frame(maxHeight: .infinity)
Color.green.frame(maxHeight: .infinity)
Color.yellow.frame(maxHeight: .infinity)
Color.blue.frame(maxHeight: .infinity)
}
Button("Show") {
isPresented = true
}
.padding()
.background(.white)
Popup(isPresented: $isPresented) {
VStack {
Button("Dismiss") {
isPresented = false
}
}
.frame(maxWidth: 300)
.padding()
.background(
RoundedRectangle(cornerRadius: 20)
.fill(.white)
)
.sheet(isPresented: $sheetPresented) {
Text("Hallo")
}
}
}
}
}
struct Popup<Content: View>: View {
@Binding var isPresented: Bool
let content: () -> Content
init(isPresented: Binding<Bool>, @ViewBuilder _ content: @escaping () -> Content) {
_isPresented = isPresented
self.content = content
}
@State private var internalIsPresented: Bool = false
@State private var isShowing: Bool = false
let transitionDuration: TimeInterval = 0.5
var body: some View {
ZStack { }
.fullScreenCover(isPresented: $internalIsPresented) {
VStack {
content()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
Color.black.opacity(0.5)
.opacity(isShowing ? 1 : 0)
.animation(.easeOut(duration: transitionDuration), value: isShowing)
.ignoresSafeArea()
)
.presentationBackground(.clear)
.onAppear {
isShowing = true
}
.onDisappear {
isShowing = false
}
}
.onChange(of: isPresented) { _ in
withoutAnimation {
internalIsPresented = isPresented
}
}
}
}
extension View {
func withoutAnimation(action: @escaping () -> Void) {
var transaction = Transaction()
transaction.disablesAnimations = true
withTransaction(transaction) {
action()
}
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
I’m building a SwiftUI app where the struct AppGroup is identified by a UUID and stored in a dictionary. My Task model has appGroupId: UUID?. In TaskDetailView, I create a custom Binding<AppGroup> from the store, then navigate to AppGroupDetailView. However, when I tap the NavigationLink, the console spams logs, CPU hits 100%, and it never stabilizes.
Relevant Code
AppGroupStore (simplified)
class AppGroupStore: ObservableObject {
@Published var appGroupsDict: [UUID: AppGroup] = [:]
func updateAppGroup(_ id: UUID, appGroup: AppGroup) {
appGroupsDict[id] = appGroup
}
// Returns a binding so views can directly read/write the AppGroup by id
func getBinding(withId id: UUID?) -> Binding<AppGroup> {
Binding(
get: {
if let id = id {
return self.appGroupsDict[id] ?? .empty
}
return .empty
},
set: { newValue in
print("New value set for \(newValue.name)")
self.updateAppGroup(newValue.id, appGroup: newValue)
}
)
}
// ...
}
AppGroup is a simple struct:
struct AppGroup: Identifiable, Codable {
let id: UUID
var name: String
var apps: [String]
static let empty = AppGroup(id: UUID(), name: "Empty", apps: [])
}
TaskDetailView (main part)
struct TaskDetailView: View {
@Binding var task: ToDoTask // has task.appGroupId: UUID?
@EnvironmentObject var appGroupStore: AppGroupStore
var body: some View {
let appGroup = appGroupStore.getBinding(withId: task.appGroupId)
print("Task load") // prints infinitely, CPU 100%
return List {
// ...
NavigationLink(destination: AppGroupDetailView(appGroup: appGroup)) {
Text(appGroup.wrappedValue.name)
}
}
.navigationTitle(task.name)
}
}
AppGroupDetailView (simplified)
struct AppGroupDetailView: View {
@Binding var appGroup: AppGroup
// ...
var body: some View {
List {
ForEach(appGroup.apps, id: \.self) { app in
Text(app)
}
}
.navigationTitle(appGroup.name)
}
}
Symptoms:
Tapping the NavigationLink leads to infinite “Task load” logs and 100% CPU usage.
The set closure (“New value set for...”) is never called, so it’s not repeatedly writing.
If I replace the Binding<AppGroup> with a read-only approach (just accessing the dictionary), it does not get stuck.
Question:
What might cause SwiftUI to keep re-rendering the body indefinitely, even if my custom get closure doesn’t explicitly mutate the state? Are there known pitfalls when using a dictionary-based store and returning a Binding like this?
Any help is much appreciated!
Thanks in advance for your insights!
In my CarPlay app, I am hiding the navigation bar by using the following:
self.mapTemplate?.automaticallyHidesNavigationBar = true
self.mapTemplate?.hidesButtonsWithNavigationBar = false
I don't want the navigation bar to show unless a user interacts with the map by tapping it.
Strangely, when I present a CPNavigationAlert the navigation bar will often appear and then disappear after the alert is dismissed.
Is there a setting or reason that the navigation bar would be appearing when presenting this alert? I would like to keep the nav bar hidden during this time.
Hello, everyone!
I'm currently working on creating tests for a study project in Swift. My current task is to create a test to check if a file is saved correctly.
The workflow in the app is as follows:
Launch the app.
Open a file within the app.
Modify the file.
Save it inside the app.
Save it to the Files app.
I need to verify if the saved file in the Files app is identical to a base file stored in the app bundle.
Initially, I thought I could solve this by creating a UI test, which I've already implemented up to a certain point. The UI test successfully navigates through the workflow steps until it's time to compare the saved file with the base file.
The problem is that I cannot open a saved file from the Files app in a UI test because it operates in a sandboxed environment and cannot interact with external app scopes.
So, my question is: What should I do in this case?
Would it be better to create a unit test specifically for testing the save function and ensure the UI test only verifies if the expected filename exists in the Files app?
I would prefer an end-to-end (E2E) test that covers the entire workflow, but it seems Swift splits tests into Unit and UI test groups, making this approach less straightforward.
Any suggestions or best practices would be greatly appreciated!
Device: iPhone 16 Pro Max
System Version: 18.3.1
Screen width and height obtained using [UIScreen mainScreen].bounds.size are as follows
Why are the two results different?
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.)
Subject: SwiftUI Gesture Conflict in iOS 18: Simultaneous Recognition of Drag and Tap Gestures
Description:
In SwiftUI on iOS 18 and above, we've identified an issue with gesture handling that affects user experience. When implementing .simultaneousGesture(DragGesture()), the system incorrectly recognizes and processes both drag and tap gestures concurrently, resulting in unintended behavior.
Technical Details:
Environment: SwiftUI, iOS 18+
Issue: Simultaneous recognition of horizontal drag gestures and vertical scroll/tap gestures
Current Behavior: Both vertical and horizontal scrolling occur simultaneously when using .simultaneousGesture(DragGesture())
Expected Behavior: Gestures should be properly disambiguated to prevent concurrent scrolling in multiple directions
Impact:
This behavior significantly impacts user experience, particularly in custom carousel implementations and other UI components that rely on precise gesture handling. The simultaneous recognition of both gestures creates a confusing and unpredictable interaction pattern.
Steps to Reproduce:
Create a SwiftUI view with horizontal scrolling (e.g., custom carousel)
Implement .simultaneousGesture(DragGesture())
Add tap gesture recognition to child views
Run on iOS 18
Attempt to scroll horizontally
Observed Result:
Both horizontal dragging and vertical scrolling/tapping are recognized and processed simultaneously, creating an inconsistent user experience.
Expected Result:
The system should properly disambiguate between horizontal drag gestures and vertical scroll/tap gestures, allowing only one type of gesture to be recognized at a time based on the user's intent.
Please let me know if you need any additional information or reproduction steps.
I am new to the idea of Siri Shortcuts and App Intents. What I want to do is use Siri to run a function in my app.
Such as saying to Siri Zoom in map and that will then call a function in my app where I can zoom in the map. Similarly, I could say Zoom out map and it would call a function to zoom out my map.
I do not need to share any sort of shortcut with the Shortcuts app.
Can someone please point me in the right direction for what type of intents I need to use for this?
When using New Password Autofill in Dark Mode, it appears that SecureEntry sets the background color to white and applies a yellow-ish overlay, but doesn't adapt the foreground text color accordingly. This gives the illusion that the SecureEntry field is empty, as we have white text on a white background.
Is there a holistic and SwiftUI-native way of fixing this?
Not sure what could cause this. the UI align differently running on iPhone versus running on Mac. If I remove the HStack, it works but I still would like to know why, and if there is a way to make it right on both platforms.
Thank you
here is my code
@State private var viewModel = FirmwareSelectionViewModel()
var body: some View {
Form {
Section("Setup Name") {
TextField ( "", text: $viewModel.setupName )
.foregroundColor(.green )
.disableAutocorrection(true)
.onSubmit {
print ("On Submit")
}
}
Section("Battery") {
HStack() {
Text("Volt")
TextField("", value: $viewModel.Vnominal, format: .number)
.textFieldStyle(.roundedBorder)
.foregroundColor(.green )
#if !os(macOS)
.keyboardType(.decimalPad)
#endif
.onChange(of: viewModel.Vnominal) {
viewModel.checkEntryValidity()
print("Updated Vnominal: \(viewModel.Vnominal)")
}
Text("Ah")
TextField("", value: $viewModel.batteryCapacity, format: .number)
.textFieldStyle(.roundedBorder)
.foregroundColor(.green )
#if !os(macOS)
.keyboardType(.decimalPad)
#endif
.onChange(of: viewModel.batteryCapacity) {
viewModel.checkEntryValidity()
print("Updated Battery Capacity: \(viewModel.batteryCapacity)")
}
}
}
Section("Firmware Type") {
Picker(selection: $viewModel.selectedType, label: EmptyView()) {
ForEach(TypeOfFirmware.allCases) { type in
Text(type.rawValue).tag(type as TypeOfFirmware)
.foregroundColor(.green )
}
}
.pickerStyle(SegmentedPickerStyle())
Picker(selection: $viewModel.selectedFirmware, label: EmptyView()) {
ForEach(viewModel.availableFirmware) { firmware in
Text(firmware.rawValue.capitalized).tag(firmware as Firmware)
}
}
.pickerStyle(SegmentedPickerStyle())
}
}
.onChange(of: viewModel.selectedType) {
viewModel.resetFirmwareSelection()
}
.navigationTitle("Firmware Selection")
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
DESCRIPTION OF PROBLEM
When using SwiftUI’s TextField or TextEditor on iPadOS, a persistent gray or default system material bar appears at the bottom of the screen. This gray bar is not present in Apple’s native apps (such as Notes, Mail, Messages) or in third-party apps like ChatGPT and Beeper
STEPS TO REPRODUCE
Create a TextField or TextEditor. Run the code, click on it, without software keyboard enabled.
I'm encountering an issue displaying a large HTML string (over 11470 characters) in a UILabel. Specifically, the Arabic text within the string is rendering left-to-right instead of the correct right-to-left direction. I've provided a truncated version of the HTML string and the relevant code snippet below. I've tried setting the UILabel's text alignment to right, but this didn't resolve the issue. Could you please advise on how to resolve this bidirectional text rendering problem?
The results of the correct and incorrect approaches are shown in the image below.
Here's the relevant Swift code:
let labelView: UILabel = {
let label = UILabel()
label.textAlignment = .right
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.semanticContentAttribute = .forceRightToLeft
label.backgroundColor = .white
label.lineBreakMode = .byWordWrapping
return label
}()
//Important!!
//It must exceed 11470 characters.
let htmlString = """
<p style=\"text-align: center;\"><strong>İSTİÂZE</strong></p> <p>Nahl sûresindeki:</p>
<p dir="rtl" lang="ar"> فَاِذَا قَرَاْتَ الْقُرْاٰنَ فَاسْتَعِذْ بِاللّٰهِ مِنَ الشَّيْطَانِ الرَّج۪يمِ </p>
<p><strong>“</strong><strong>Kur’an okuyacağın zaman kovulmuş şeytandan hemen Allah’a sığın!</strong><strong>”</strong> (Nahl 16/98) emri gereğince Kur’ân-ı Kerîm okumaya başlarken:</p> <p dir="rtl" lang="ar">اَعُوذُ بِاللّٰهِ مِنَ الشَّيْطَانِ الرَّج۪يمِ</p> <p><em>“Kovulmuş şeytandan Allah’a sığınırım” </em>deriz. Bu sözü söylemeye “istiâze<em>” denilir. “Eûzü”</em>, sığınırım, emân dilerim, yardım taleb ederim, gibi anlamlara gelir. It must exceed 11470 characters.</p>
“””
if let data = htmlString.data(using: .utf8) {
let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue
]
do {
let attributedString = try NSAttributedString(data: data, options: options, documentAttributes: nil)
labelView.attributedText = attributedString
} catch {
print("HTML string işlenirken hata oluştu: \(error)")
}
}
I'm using iOS 18.2 and Swift 6. Any suggestions on how to correct the bidirectional text rendering?
Description:
When initiating the print flow via UIPrintInteractionController, and no printer is initially connected, iOS displays all possible paper sizes in the paper selection UI. However, if a printer connects in the background after this view is shown, the list of paper sizes does not automatically refresh to reflect only the options supported by the connected printer.
If the user selects an incompatible paper size (one not supported by the printer that has just connected), the app crashes due to an invalid configuration.
Steps to Reproduce:
Launch the app and navigate to the print functionality.
Tap the Print button to invoke UIPrintInteractionController.
At this point, no printer is yet connected. iOS displays all available paper sizes.
While the paper selection UI is visible, the AirPrint-compatible printer connects in the background.
Without dismissing the controller, the user selects a paper size (e.g., one that is not supported by the printer).
The app crashes.
Expected Result: App should not crash
Once the printer becomes available (connected in the background), the paper size options should refresh automatically.
The list should be filtered to only include sizes that are compatible with the connected printer.
This prevents the user from selecting an invalid option, avoiding crashes.
Actual Result: App crashes
The paper size list remains unfiltered.
The user can still select unsupported paper sizes.
Selecting an incompatible option causes the app to crash, due to a mismatch between UI selection and printer capability.
Topic:
UI Frameworks
SubTopic:
UIKit
I have an app on the Mac App Store (so sandboxed) that includes a QuickLook Preview Extension that targets Markdown files. It established a QLPreviewingController instance for the macOS QuickLook system to access and it works.
I'm in the process of updating it so that it displays inline images referenced in the file as well as styling the file's text. However, despite setting Downloads folder read-only access permission (and user-selected, though I know that shouldn't be required: no open/save dialogs here) in the extension's entitlements, Sandbox refuses too allow access to the test image: I always get a deny(1) file-read-data error in the log.
FWIW, the test file is referenced in the source Markdown as an absolute unix file path.
I've tried different signings and no joy. I’ve tried placing the referenced image in various other locations. Also no joy. All I can display is the error-case bundle image for 'missing image'.
Question is, is this simply something that QuickLook extensions cannot do from within the sandbox, or am I missing something? Is there anything extra I can do to debug this?
I'm wondering what the correct, or recommended, way is to dismiss a SwiftUI that is being presented as a sheet hosted by an NSHostingController. The usual technique of invoking @Environment(\.dismiss) does not appear to work.
Consider the code below. An NSWindowController is attempting to display a SwiftUI SettingsView as a sheet. The sheet is correctly presented, but the SettingsView is unable to dismiss itself.
I am able to make it work by passing a closure into SettingsView that calls back to the NSWindowController but it's rather convoluted because SettingsView doesn't know the view controller that's hosting it until after SettingsView has been created, which means "finding" that view controller in the window controller to dismiss is more involved than it should be.
Is there a better strategy to leverage here?
final class MyViewController: NSViewController {
@IBAction func buttonClicked(_ sender: NSButton) {
if let presenter = window?.contentViewController {
presenter.presentAsSheet(NSHostingController(rootView: SettingsView()))
}
}
}
struct SettingsView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
VStack {
Button("Cancel", role: .cancel) {
dismiss() // This call does not dismiss the sheet.
} .keyboardShortcut(.cancelAction)
}
}
}
Thank you.
macOS 15.4.1 (24E263), Xcode 16.3 (16E140)