Post

Replies

Boosts

Views

Activity

Are SwiftUI Text views with empty strings optimized out in iOS 18?
A UI test case that checks for the existence of a SwiftUI Text element initialized with an empty string previously reliably passed in iOS 17. In iOS 18 the assertion reliably fails. I searched the iOS 18 developer release notes for anything possibly related to this but didn't find much. I'd like to point to a conclusive change in iOS handling before changing the test permantently. Can anyone confirm that this is indeed a change in iOS 18?
0
3
152
3w
ARKit delegate code broken by Swift 6
I'm porting over some code that uses ARKit to Swift 6 (with Complete Strict Concurrency Checking enabled). Some methods on ARSCNViewDelegate, namely Coordinator.renderer(_:didAdd:for:) among at least one other is causing a consistent crash. On Swift 5 this code works absolutely fine. The above method consistently crashes with _dispatch_assert_queue_fail. My assumption is that in Swift 6 a trap has been inserted by the compiler to validate that my downstream code is running on the main thread. In Implementing a Main Actor Protocol That’s Not @MainActor, Quinn “The Eskimo!” seems to address scenarios of this nature with 3 proposed workarounds yet none of them seem feasible here. For #1, marking ContentView.addPlane(renderer:node:anchor:) nonisolated and using @preconcurrency import ARKit compiles but still crashes :( For #2, applying @preconcurrency to the ARSCNViewDelegate conformance declaration site just yields this warning: @preconcurrency attribute on conformance to 'ARSCNViewDelegate' has no effect For #3, as Quinn recognizes, this is a non-starter as ARSCNViewDelegate is out of our control. The minimal reproducible set of code is below. Simply run the app, scan your camera back and forth across a well lit environment and the app should crash within a few seconds. Switch over to Swift Language Version 5 in build settings, retry and you'll see the current code works fine. import ARKit import SwiftUI struct ContentView: View { @State private var arViewProxy = ARSceneProxy() private let configuration: ARWorldTrackingConfiguration @State private var planeFound = false init() { configuration = ARWorldTrackingConfiguration() configuration.worldAlignment = .gravityAndHeading configuration.planeDetection = [.horizontal] } var body: some View { ARScene(proxy: arViewProxy) .onAddNode { renderer, node, anchor in addPlane(renderer: renderer, node: node, anchor: anchor) } .onAppear { arViewProxy.session.run(configuration) } .onDisappear { arViewProxy.session.pause() } .overlay(alignment: .top) { if !planeFound { Text("Slowly move device horizontally side to side to calibrate") } else { Text("Plane found!") .bold() .foregroundStyle(.green) } } } private func addPlane(renderer: SCNSceneRenderer, node: SCNNode, anchor: ARAnchor) { guard let planeAnchor = anchor as? ARPlaneAnchor, let device = renderer.device, let planeGeometry = ARSCNPlaneGeometry(device: device) else { return } planeFound = true planeGeometry.update(from: planeAnchor.geometry) let material = SCNMaterial() material.isDoubleSided = true material.diffuse.contents = UIColor.white.withAlphaComponent(0.65) planeGeometry.materials = [material] let planeNode = SCNNode(geometry: planeGeometry) node.addChildNode(planeNode) } } struct ARScene { private(set) var onAddNodeAction: ((SCNSceneRenderer, SCNNode, ARAnchor) -> Void)? private let proxy: ARSceneProxy init(proxy: ARSceneProxy) { self.proxy = proxy } func onAddNode( perform action: @escaping (SCNSceneRenderer, SCNNode, ARAnchor) -> Void ) -> Self { var view = self view.onAddNodeAction = action return view } } extension ARScene: UIViewRepresentable { func makeUIView(context: Context) -> ARSCNView { let arView = ARSCNView() arView.delegate = context.coordinator arView.session.delegate = context.coordinator proxy.arView = arView return arView } func updateUIView(_ uiView: ARSCNView, context: Context) { context.coordinator.onAddNodeAction = onAddNodeAction } func makeCoordinator() -> Coordinator { Coordinator() } } extension ARScene { class Coordinator: NSObject, ARSCNViewDelegate, ARSessionDelegate { var onAddNodeAction: ((SCNSceneRenderer, SCNNode, ARAnchor) -> Void)? func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { onAddNodeAction?(renderer, node, anchor) } } } @MainActor class ARSceneProxy: NSObject, @preconcurrency ARSessionProviding { fileprivate var arView: ARSCNView! @objc dynamic var session: ARSession { arView.session } } Any help is greatly appreciated!
1
7
321
Oct ’24
View in a NavigationSplitView detail looses navigation ToolbarItem after rotation
A ToolbarItem with navigationBar* placement disappears when placed in a toolbar on a detail view of NavigationSplitView. Expectation: The toolbar item doesn't disappear after device rotation. Reality: The toolbar item disappears after device rotation. Reproducible on iPhone 15 Pro Max simulator running 17.4 import SwiftUI @main struct MyApp: App { @State private var selection: Int? @State private var visibility: NavigationSplitViewVisibility = .detailOnly var body: some Scene { WindowGroup { NavigationSplitView(columnVisibility: $visibility) { List(1..<10, selection: $selection) { number in NavigationLink(value: number) { Button(number.description) { selection = number } } } } detail: { if let selection { LinearGradient(colors: [.blue, .black], startPoint: .top, endPoint: .bottom) .navigationTitle(selection.description) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Text("A button") } } } else { Text("Please make a selection") } } } } } The problem doesn't exhibit itself when using a NavigationStack instead. import SwiftUI @main struct MyApp: App { @State private var selection: Int? var body: some Scene { WindowGroup { NavigationStack { List(1..<10) { number in NavigationLink(value: number) { Button(number.description) { selection = number } } } .navigationDestination(for: Int.self) { selection in LinearGradient(colors: [.blue, .black], startPoint: .top, endPoint: .bottom) .navigationTitle(selection.description) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Text("A button") } } } } } } }
1
0
307
Apr ’24
TextFields need a way to keep the input caret visible
If a TextField is being used within a ScrollView, when the TextField becomes tall enough the input caret can go offscreen behind the keyboard. There's no straightforward way to keep the caret visible. One could use .id(_:) on something at the bottom of the TextField and scroll to that with the ScrollViewProxy but how would they know when to scroll? They could detect a height change of the TextField but if the user is typing towards the center of the field then we end up scrolling them away from their edit location to the bottom. They could detect a length change in the edited text but that has the same issue as #1. They could diff the edited text to see if the edits were at the end but then we're getting much more complex. TLDR: We need a straightforward way to keep the TextField's input caret visible. What I could see working would be something like a modifier for TextField like .cursorID(_:). We could then just scroll to that ID on input changes. Here's a similar post on StackOverflow.
0
3
259
Mar ’24
DatePicker time input cutoff
FB13699023 A conditionally shown DatePicker with .datePickerStyle(.graphical) has the time input cutoff until a new selection is made. Repro steps: Tap “Select a date” to show the conditionally hidden DatePicker. What happens: The time input is cutoff. What I expect: The time input is not cutoff. Choose a new date. The time input is shown as expected. Tested on a 9th gen iPad running 17.4.1, a iPhone 15 Pro Max simulator running 17.4 Using Xcode Version 15.3 (15E204a) struct ContentView: View { @State private var selection = Date.now @State private var isOpen = false var body: some View { Button("Select a date") { isOpen.toggle() } if isOpen { DatePicker("Date Picker", selection: $selection) .datePickerStyle(.graphical) } } }
0
2
323
Mar ’24
Are calls to begin and end generating device orientation notifications necessary?
UIDevice.orientationDidChangeNotification works as expected without calls to beginGeneratingDeviceOrientationNotifications() and endGeneratingDeviceOrientationNotifications() but the respective documentation for these two methods state: You must call this method before attempting to get orientation data from the device. and You call this method after a previous call to the beginGeneratingDeviceOrientationNotifications() method. Were they a requirement at one time and never deprecated?
0
0
322
Jan ’24
How to create iOS 15.x simulators in Xcode 15
I'm using Xcode 15.0 (15A240d) and I need to test some code on iOS 15. I'm unable to create a new iOS 15 simulator. If I select the "Download more" option I'm presented with the "Platforms" tab in settings. There's no option to actually select a platform here (which as you can see Xcode itself indicates I have on disk). Neither double-click nor secondary-click do anything for me either. Am I doing something wrong or is this just bad design?
0
0
1.8k
Nov ’23
Crash when triggering sheet presentation from a task
Given the following code, if line 17 isn't present there'll be a crash upon presenting the sheet. Since content shouldn't be nil at the time of presentation, why does this crash? import SwiftUI struct ContentView: View { @State private var isPresented = false @State private var content: String? @State private var startTask = false var body: some View { Text("Tap me") .onTapGesture { startTask = true } .task(id: startTask) { guard startTask else { return } startTask = false // <===== Crashes if removed content = "Some message" isPresented = true } .sheet(isPresented: $isPresented) { Text(content!) } } } iOS 16.4, Xcode 14.3.1
6
0
775
Aug ’23
Xcode 15 Breaks Usage Of TextField.focused()
My usage of TextField.focused() works fine in Xcode 14.3.1 but is broken as of Xcode 15. I first noticed it in the second beta and it's still broken as of the 4th beta. Feedback / OpenRadar # FB12432084 import SwiftUI struct ContentView: View { @State private var text = "" @FocusState var isFocused: Bool var body: some View { ScrollView { TextField("Test", text: $text) .textFieldStyle(.roundedBorder) .focused($isFocused) Text("Text Field Is Focused: \(isFocused.description)") } } }
6
1
1.3k
Jul ’23
SwiftUI LibraryItem instances can produce unexpected results
When passing an empty closure to a LibraryItem's snippet parameter, unexpected extra text is added to the file when the item is dragged in from the Xcode library. Expected: .setAction { } Actual: .setAction /*@START_MENU_TOKEN@*/{ }/*@END_MENU_TOKEN@*/ Full code: import SwiftUI struct ContentView: View {   var body: some View {     MyView()   } } struct ContentView_Previews: PreviewProvider {   static var previews: some View {     ContentView()   } } struct MyView: View {   var action: (() -> Void)?       var body: some View {     Text("MyView")       .onTapGesture {         action?()       }   }       func setAction(_ action: @escaping () -> Void) -> MyView {     var copy = self     copy.action = action     return copy   } } struct LibraryContent: LibraryContentProvider {   func modifiers(base: MyView) -> [LibraryItem] {     [       LibraryItem(         base.setAction {                     },         title: "MyView - Set action"       )     ]   } } FB11936092 macOS 13.0.1 (22A400) Xcode 14.1 (14B47b)
0
0
559
Jan ’23
iOS 16.0 breaks GeometryReader or UIDevice.orientationDidChangeNotification notifications
In iOS 15.5 the correct GeometryProxy.size.height value is available when a UIDevice.orientationDidChangeNotification is received. In iOS 16.0 the GeometryProxy.size.height value is outdated it (reflects the value before rotation). Expected behavior: iPhone SE (3rd generation) (15.5) Landscape: Height is logged at 375.0. Portrait: Height is logged at 647.0. Actual behavior: iPhone SE (3rd generation) (16.0) Landscape: Height is logged at 647.0. Portrait: Height is logged at 375.0. Feedback FB10448199 import SwiftUI struct ContentView: View {   let orientationDidChangeNotification =     NotificationCenter       .default       .publisher(for: UIDevice.orientationDidChangeNotification)       var body: some View {     GeometryReader { geometryProxy in       Color.clear         .onReceive(orientationDidChangeNotification) { _ in           print(geometryProxy.size.height)         }     }   } }
1
3
1.2k
Jun ’22