I'm implementing a Map with user location customization in SwiftUI using iOS 17+ MapKit APIs. When using the selection parameter with Map, the default blue dot user location becomes tappable but shows an empty annotation view. However, using UserAnnotation makes the location marker non-interactive.
My code structure:
import SwiftUI
import MapKit
struct UserAnnotationSample: View {
@State private var position: MapCameraPosition = .userLocation(fallback: .automatic)
@State private var selectedItem: MapSelection<MKMapItem>?
var body: some View {
Map(position: $position, selection: $selectedItem) {
// UserAnnotation()
}
.mapControls {
MapUserLocationButton()
}
}
}
Key questions:
How can I replace the empty annotation view with a custom avatar when tapping the user location?
Is there a way to make UserAnnotation interactive with selection?
Should I use tag modifier for custom annotations? What's the proper way to associate selections?
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
We are looking at the possibility of launching our app through Siri with a locked device. We have the device responding to our App Intent but it is asking to be unlocked first. If the device is locked the intent works perfectly. It just doesn't seem to respect the set intentAuthenticationPolicy.
Thank you for you time looking into this.
We have set these var to .alwaysAllowed and open to true.
static var authenticationPolicy: IntentAuthenticationPolicy = .alwaysAllowed
static var openAppWhenRun: Bool = true
Here is our full test code:
import AppIntents
import SwiftUI
// MARK: - App Intents
struct OpenAppIntent: AppIntent {
static var title: LocalizedStringResource = "Open Main App"
static var description: IntentDescription? = .init(stringLiteral: "Opens the App")
static var authenticationPolicy: IntentAuthenticationPolicy = .alwaysAllowed
static var openAppWhenRun: Bool = true
func perform() async throws -> some IntentResult {
print("App opened")
return .result()
}
}
struct TestAppShortcutProvider: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: OpenAppIntent(),
phrases: [
"Begin \(.applicationName)"
],
shortTitle: "Open App",
systemImageName: "popcorn.fill"
)
}
}
I have received permission from Apple to access SensorKit data for my app. I have granted all necessary permissions, but no data is being retrieved.
The didCompleteFetch method is being called, but I’m unsure where to find event data like Device Usage and Ambient Light. Additionally, the didFetchResult method is never called.
Could anyone please assist me in resolving this issue? Any guidance or troubleshooting steps would be greatly appreciated.
import SensorKit
class ViewController: UIViewController, SRSensorReaderDelegate {
let store = SRSensorReader(sensor: .deviceUsageReport)
override func viewDidLoad() {
super.viewDidLoad()
requestSensorAuthorization()
}
func requestSensorAuthorization() {
var sensors: Set<SRSensor> = [
.accelerometer,
.deviceUsageReport,
.messagesUsageReport,
.visits,
.keyboardMetrics,
.phoneUsageReport,
.ambientLightSensor
]
if #available(iOS 16.4, *) {
sensors.insert(.mediaEvents)
}
SRSensorReader.requestAuthorization(sensors: sensors) { error in
if let error = error {
print("Authorization failed: \(error.localizedDescription)")
} else {
self.store.startRecording()
self.requestSensorData()
print("Authorization granted for requested sensors.")
}
}
}
func requestSensorData() {
let fromTime = SRAbsoluteTime.fromCFAbsoluteTime(_cf: Date().addingTimeInterval(-60 * 60).timeIntervalSinceReferenceDate)
let toTime = SRAbsoluteTime.fromCFAbsoluteTime(_cf: Date().timeIntervalSinceReferenceDate)
let request = SRFetchRequest()
request.from = fromTime
request.to = toTime
request.device = SRDevice.current
store.fetch(request)
store.delegate = self
}
func sensorReader(_ reader: SRSensorReader, didCompleteFetch fetchRequest: SRFetchRequest) {
print("Fetch request completed: \(fetchRequest.from) to \(fetchRequest.to)")
Task {
do {
let samples = try await reader.fetch(fetchRequest)
print("Samples count: \(samples)")
} catch {
print("Error Fetching Data: \(error.localizedDescription)")
}
}
}
func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject>) -> Bool {
print(result)
return true
}
}
There's an easily reproducible SwiftUI bug on macOS where an app's UI state no longer updates/re-renders for "Designed for iPad" apps (i.e. ProcessInfo.processInfo.isiOSAppOnMac == true). The bug occurs in Xcode and also if the app is running independent of Xcode.
The bug occurs when:
the user Hides the app (i.e. it goes into the background)
the user puts the Mac to sleep (e.g. Apple menu > Sleep)
a total of ~60 seconds transpires (i.e. macOS puts the app into the "suspended state")
when the app is brought back into the foreground the UI no longer updates properly
The only way I have found to fix this is to manually open a new actual full app window via File > New, in which case the app works fine again in the new window.
The following extremely simple code in a default Xcode project illustrates the issue:
import SwiftUI
@main
struct staleApp: App {
@State private var isBright = true
var body: some Scene {
WindowGroup() {
ZStack {
(isBright ? Color.white : Color.black).ignoresSafeArea()
Button("TOGGLE") { isBright.toggle(); print("TAPPED") }
}
.onAppear { print("\(isBright ? "light" : "dark") view appeared") }
}
}
}
For the code above, after Hiding the app and putting the computer to sleep for 60 seconds or more, the button no longer swaps views, although the print statements still appear in the console upon tapping the button. Also, while in this buggy state, i can get the view to update to the current state (i.e. the view triggered by the last tap) by manually dragging the corner of the app window to resize the window. But after resizing, the view again does not update upon button tapping until I resize the window again.
so it appears the diff engine is mucked or that the Scene or WindowGroup are no longer correctly running on the main thread
I have tried rebuilding the entire view hierarchy by updating .id() on views but this approach does NOT work. I have tried many other options/hacks but have not been able to reset the 'view engine' other than opening a new window manually or by using: @Environment(.openWindow) private var openWindow
openWindow could be a viable solution except there's no way to programmatically close the old window for isiOSAppOnMac (@Environment(.dismissWindow) private var dismissWindow doesn't work for iOS)
In UIKit, certain events like a button tap can be simulated using:
button.sendActions(for: .touchUpInside)
This allows us to trigger the button’s action programmatically.
However, in SwiftUI, there is no direct equivalent of sendActions(for:) for views like Button. What is the recommended approach to programmatically simulate a SwiftUI button tap and trigger its action?
Is there an alternative mechanism to achieve this(and for other events under UIControl.event) , especially in scenarios where we want to test interactions or trigger actions without direct user input?
Seeing weird sequences of changes when locking the screen when view is visable.
.onChange(of: scenePhase) { phase in
if phase == .active {
if UIApplication.shared.applicationState == .active {
print("KDEBUG: App genuinely became active")
} else {
print("KDEBUG: False active signal detected")
}
} else if phase == .inactive {
print("KDEBUG: App became inactive")
// Handle inactive state if needed
} else if phase == .background {
print("KDEBUG: App went to background")
// Handle background state if needed
}
}
seen:
(locks screen)
KDEBUG: App became inactive
KDEBUG: App genuinely became active
KDEBUG: App went to background
expected
(locks screen)
KDEBUG: App became inactive
KDEBUG: App went to background
I have the MainView as the active view if the user is logged in(authenticated). the memory allocations when we run profile is pretty good. We have graphql fetching, we have token handling eg: This is All heap:
1 All Heap & Anonymous VM 13,90 MiB 65408 308557 99,10 MiB 373965 Ratio: %0.14, %0.86
After what i have checked this is pretty good for initialise and using multiple repositories eg. But when we change tabs:
1 All Heap & Anonymous VM 24,60 MiB 124651 543832 156,17 MiB 668483 Ratio: %0.07, %0.40
And that is not pretty good. So i guess we need to "kill" it or something. How? I have tried some techniques in a forum this was a recommended way:
public struct LazyView<Content: View>: View {
private let build: () -> Content
@State private var isVisible = false
public init(_ build: @escaping () -> Content) {
self.build = build
}
public var body: some View {
build()
Group {
if isVisible {
build()
} else {
Color.clear
}
}
.onAppear { isVisible = true }
.onDisappear { isVisible = false }
}
}
But this did not help at all. So under here is the one i use now. So pleace guide me for making this work.
import DIKit
import CoreKit
import PresentationKit
import DomainKit
public struct MainView: View {
@Injected((any MainViewModelProtocol).self) private var viewModel
private var selectedTabBinding: Binding<MainTab> {
Binding(
get: { viewModel.selectedTab },
set: { viewModel.selectTab($0) }
)
}
public init() {
// No additional setup needed
}
public var body: some View {
NavigationStack(path: Binding(
get: { viewModel.navigationPath },
set: { _ in }
)) {
TabView(selection: selectedTabBinding) {
LazyView {
FeedTabView()
}
.tabItem {
Label("Feed", systemImage: "house")
}
.tag(MainTab.feed)
LazyView {
ChatTabView()
}
.tabItem {
Label("Chat", systemImage: "message")
}
.tag(MainTab.chat)
LazyView {
JobsTabView()
}
.tabItem {
Label("Jobs", systemImage: "briefcase")
}
.tag(MainTab.jobs)
LazyView {
ProfileTabView()
}
.tabItem {
Label("Profile", systemImage: "person")
}
.tag(MainTab.profile)
}
.accentColor(.primary)
.navigationDestination(for: MainNavigationDestination.self) { destination in
switch destination {
case .profile(let userId):
Text("Profile for \(userId)")
case .settings:
Text("Settings")
case .jobDetails(let id):
Text("Job details for \(id)")
case .chatThread(let id):
Text("Chat thread \(id)")
}
}
}
}
}
import SwiftUI
public struct LazyView<Content: View>: View {
private let build: () -> Content
public init(_ build: @escaping () -> Content) {
self.build = build
}
public var body: some View {
build()
}
}
Where from and how does an NSRulerView get its magnification from? I am not using the automatic magnification by NSScrollView but using my own mechanism. How do I relay the zoom factor to NSRulerView?
Hello, I've managed to get rid of these spaces in different ways. Using scrollview, giving negative insets, rewriting modifiers from scratch with plain style etc. But I couldn't solve this with a simple solution. I've read comments from many people experiencing similar problems online. It seems like there isn't a simple modifier to remove these spaces when we use sidebar as the list style in SwiftUI, or I couldn't find the simple solution.
I wonder what's the simplest and correct way to reset these spaces?
let numbers = Array(1...5)
@State private var selected: Int?
var body: some View {
List(numbers, id: \.self, selection: $selected) { number in
HStack {
Text("Test")
Spacer()
}
.frame(maxWidth: .infinity, alignment: .leading)
}
.listStyle(.sidebar)
}
}
When using FileImporter in SwiftUI, the following error is always returned when closed; even if the user taps "Cancel"
The view service did terminate with error: Error Domain=_UIViewServiceErrorDomain Code=1 "(null)" UserInfo={Terminated=disconnect method}
Recreation rate is 10/10. It feels like a threading issue, but in SwiftUI we are leveraging the .fileImporter modifier, so we cannot hold on to the reference like we would in a class.
Is there a different approach we should be using for this?
Code for recreation
import SwiftUI
struct ContentView: View {
@State private var fileURL: URL?
@State private var showFileImporter: Bool = false
var body: some View {
VStack {
if let fileURL {
Text(fileURL.absoluteString)
}
Button {
showFileImporter = true
} label: {
Text("Select PDF")
}
.fileImporter(
isPresented: $showFileImporter,
allowedContentTypes: [.pdf],
allowsMultipleSelection: true
) { result in
switch result {
case .success(let files):
files.forEach { file in
let gotAccess = file.startAccessingSecurityScopedResource()
if !gotAccess { return }
fileURL = file
file.stopAccessingSecurityScopedResource()
}
case .failure(let error):
print(error)
}
}
}
}
}
I want to truncate text from head with max 2 lines.
I try the following code
import SwiftUI
struct ContentView: View {
@State var content: String = "Hello world! wef wefwwfe wfewe weweffwefwwfwe wfwe"
var body: some View {
VStack {
Text(content)
.lineLimit(nil)
.truncationMode(.head)
.frame(height: 50)
Button {
content += content
} label: {
Text("Double")
}
.buttonStyle(.borderedProminent)
}
.frame(width: 200, height: 1000)
.padding()
}
}
#Preview {
ContentView()
}
It show result like this, this is not what I want.
All the threads only contain system calls. The crashed thread only contains a single call to my app's code which is main.swift:13.
What could cause such a crash?
crash.crash
Hello.
I am currently building an app using AR Kit.
As for the UI, I am using SwiftUI and NavigationStack + NavigationLink for navigation and screen transitions!
Here I need to go back and forth between the AR screen and other screens.
If the number of screen transitions is small, this is not a problem.
However, if the number of screen transitions increases to 10 or 20, it crashes somewhere.
We are struggling with this problem. (The nature of the application requires multiple screen transitions.)
The crash log showed the following.
error: read memory from 0x1e387f2d4 failed
AR_Crash_Sample-2025-03-07-115914.txt
Incident Identifier: B23D806E-D578-4A95-8828-2A1E8D6BB7F8
Beta Identifier: 924A85AB-441C-41A7-9BC2-063940BDAF32
Hardware Model: iPhone16,1
Process: AR_Crash_Sample [2375]
Path: /private/var/containers/Bundle/Application/FAC3D662-DB10-434E-A006-79B9515D8B7A/AR_Crash_Sample.app/AR_Crash_Sample
Identifier: ar.crash.sample.AR.Crash.Sample
Version: 1.0 (1)
AppStoreTools: 16C7015
AppVariant: 1:iPhone16,1:18
Beta: YES
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: ar.crash.sample.AR.Crash.Sample [1464]
Date/Time: 2025-03-07 11:59:14.3691 +0900
Launch Time: 2025-03-07 11:57:47.3955 +0900
OS Version: iPhone OS 18.3.1 (22D72)
Release Type: User
Baseband Version: 2.40.05
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: SIGNAL 6 Abort trap: 6
Terminating Process: AR_Crash_Sample [2375]
Triggered by Thread: 7
Application Specific Information:
abort() called
Thread 7 name: Dispatch queue: com.apple.arkit.depthtechnique
Thread 7 Crashed:
0 libsystem_kernel.dylib 0x1e387f2d4 __pthread_kill + 8
1 libsystem_pthread.dylib 0x21cedd59c pthread_kill + 268
2 libsystem_c.dylib 0x199f98b08 abort + 128
3 libc++abi.dylib 0x21ce035b8 abort_message + 132
4 libc++abi.dylib 0x21cdf1b90 demangling_terminate_handler() + 320
5 libobjc.A.dylib 0x18f6c72d4 _objc_terminate() + 172
6 libc++abi.dylib 0x21ce0287c std::__terminate(void (*)()) + 16
7 libc++abi.dylib 0x21ce02820 std::terminate() + 108
8 libdispatch.dylib 0x199edefbc _dispatch_client_callout + 40
9 libdispatch.dylib 0x199ee65cc _dispatch_lane_serial_drain + 768
10 libdispatch.dylib 0x199ee7158 _dispatch_lane_invoke + 432
11 libdispatch.dylib 0x199ee85c0 _dispatch_workloop_invoke + 1744
12 libdispatch.dylib 0x199ef238c _dispatch_root_queue_drain_deferred_wlh + 288
13 libdispatch.dylib 0x199ef1bd8 _dispatch_workloop_worker_thread + 540
14 libsystem_pthread.dylib 0x21ced8680 _pthread_wqthread + 288
15 libsystem_pthread.dylib 0x21ced6474 start_wqthread + 8
Perhaps I am using too much memory!
How can I address this phenomenon?
For the AR functionality, we are using UIViewRepresentable, which is written in UIKit and can be called from SwiftUI
import ARKit
import AsyncAlgorithms
import AVFoundation
import SCNLine
import SwiftUI
internal struct MeasureARViewContainer: UIViewRepresentable {
@Binding var tapCount: Int
@Binding var distance: Double?
@Binding var currentIndex: Int
var focusSquare: FocusSquare = FocusSquare()
let coachingOverlay: ARCoachingOverlayView = ARCoachingOverlayView()
func makeUIView(context: Context) -> ARSCNView {
let arView: ARSCNView = ARSCNView()
arView.delegate = context.coordinator
let configuration: ARWorldTrackingConfiguration = ARWorldTrackingConfiguration()
configuration.planeDetection = [.horizontal, .vertical]
if ARWorldTrackingConfiguration.supportsFrameSemantics(.sceneDepth) {
configuration.frameSemantics = [.sceneDepth, .smoothedSceneDepth]
}
arView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
context.coordinator.sceneView = arView
context.coordinator.scanTarget()
coachingOverlay.session = arView.session
coachingOverlay.delegate = context.coordinator
coachingOverlay.goal = .horizontalPlane
coachingOverlay.activatesAutomatically = true
coachingOverlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
coachingOverlay.translatesAutoresizingMaskIntoConstraints = false
arView.addSubview(coachingOverlay)
return arView
}
func updateUIView(_ _: ARSCNView, context: Context) {
context.coordinator.mode = MeasurementMode(rawValue: currentIndex) ?? .width
if tapCount == 0 {
context.coordinator.resetMeasurement()
return
}
if distance != nil {
return
}
DispatchQueue.main.async {
if context.coordinator.distance == nil {
context.coordinator.handleTap()
}
}
}
static func dismantleUIView(_ uiView: ARSCNView, coordinator: Coordinator) {
uiView.session.pause()
coordinator.stopScanTarget()
coordinator.stopSpeech()
DispatchQueue.main.async {
uiView.removeFromSuperview()
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, ARSCNViewDelegate, ARSessionDelegate, ARCoachingOverlayViewDelegate {
var parent: MeasureARViewContainer
var sceneView: ARSCNView?
var startPosition: SCNVector3?
var pointedCount: Int = 0
var distance: Float?
var mode: MeasurementMode = .width
let synthesizer: AVSpeechSynthesizer = AVSpeechSynthesizer()
var scanTargetTask: Task<Void, Never>?
var currentResult: ARRaycastResult?
init(_ parent: MeasureARViewContainer) {
self.parent = parent
}
// ... etc
}
}
Hello,
In my SwiftUI App i'm trying to create a custom UI trait and a matching bridged SwiftUI environment key. I want to override the environment key in a swift view and then have that reflect in the current UITraitCollection.
I'm following the pattern in the linked video but am not seeing the changes reflect in the current trait collection when I update the swift env value.
I can't find anything online that is helping.
Does anyone know what I am missing?
https://developer.apple.com/videos/play/wwdc2023/10057/
// Setup
enum CustomTheme: String, Codable {
case theme1 = “theme1”,
theme2 = “theme2”
}
struct customThemeTrait: UITraitDefinition {
static let defaultValue = brand.theme1
static let affectsColorAppearance = true
static let identifier = "com.appName.customTheme"
}
extension UITraitCollection {
var customTheme: CustomTheme { self[customThemeTrait.self] }
}
extension UIMutableTraits {
var customTheme: CustomTheme {
get { self[customThemeTrait.self] }
set { self[customThemeTrait.self] = newValue }
}
}
private struct customThemeKey: EnvironmentKey {
static let defaultValue: CustomTheme = .theme1
}
extension customThemeKey: UITraitBridgedEnvironmentKey {
static func read(from traitCollection: UITraitCollection) -> CustomTheme {
traitCollection.customTheme
}
static func write(to mutableTraits: inout UIMutableTraits, value: CustomTheme) {
mutableTraits.customTheme = value
}
}
extension EnvironmentValues {
var customTheme: CustomTheme {
get { self[customThemeKey.self] }
set { self[customThemeKey.self] = newValue }
}
}
// Attempted Usage
extension Color {
static func primaryBackground() -> Color {
UITraitCollection.current.customTheme == .theme1 ? Color.red : Color.blue
}
}
struct ContentView: View {
@State private var theme = .theme1
var body: some View {
if (dataHasLoaded && themeIsSet) {
HomeView()
.environment(\.customTheme, theme)
} else {
SelectThemeView( theme: self.theme, setContentThemeHandler)
}
}
func setContentThemeHandler(theme: customTheme) {
self.theme = theme
}
}
struct HomeView() {
@Environment(\.customTheme) private var currentTheme: customTheme
var body: some View {
VStack {
Text("currentTheme: \(currentTheme.rawValue)")
.background(Color.primaryBackground())
Text("currentUITrait: \(UITraitCollection.current.customTheme.rawValue)")
.background(Color.primaryBackground())
}
}
}
OUTCOME:
After selecting theme2 in the theme selector view and navigating to the homeView, the background is still red and the env and trait values print the following:
currentTheme: theme2
currentUITrait: theme1
Can anyone help me identify what I am missing?
I have a UITextField in my application, and I want to detect all the keys uniquely to perform all relevant task. However, there is some problem in cleanly identifying some of the keys.
I m not able to identify the backspace key press in the textField(_:shouldChangeCharactersIn:replacementString:) method.
Also I don't know how to detect the Caps Lock key.
I am intending to so this because I want to perform some custom handling for some keys. Can someone help me with what is the way of detecting it under the recommendation from apple. Thanks in advance.
Note: checking for replacementString parameter in shouldChangeCharactersIn method for empty does not help for backspace detection as it overlaps with other cases.
The Problem
Push buttons (created as a PDFAnnotation using PDFKit) do not properly write the associated caption's key-value pair (within the annotation's appearance characteristics dictionary) to a PDF document.
What is Happening
Push button widget annotations can have a caption that is displayed as the button’s label.
In the PDF 1.7 specification (ISO PDF32000-2008, s. 12.5.6.19), a widget annotation can have an ‘appearance characteristics dictionary’ (MK) with properties to construct the appearance of the widget. The caption property (CA) is used to construct a button’s caption/label.
PDFKit uses the PDFAnnotation .caption property to set the value of a push button’s caption as a string.
Observation 1:
In an open PDF document (using PDFView), a push button widget annotation can be created and added to a PDFPage using the following code:
let pushButton = PDFAnnotation(bounds: pushButtonBounds, forType: .widget, withProperties: nil)
pushButton.widgetFieldType = .button
pushButton.widgetControlType = .pushButtonControl
pushButton.caption = "My Button"
page.addAnnotation(pushButton)
The PDFAnnotation .caption property is used to set the caption to the required string. As a result, the push button is correctly displayed on the PDFPage with the correct label being display on the button.
While the PDF document remains open, the appearance characteristics dictionary (an PDFAppearanceCharacteristics object) retains a key-value pair for the caption with the correct value as expected.
On saving/writing to the PDF file, however, the key-value pair for the caption in the appearance characteristics dictionary is not written to the PDF document’s file.
Resulting PDF markup:
6 0 obj
<< /Rect [ 256 299.8977 356 399.8977 ] /Border [ 0 0 0 ] /T (button23) /F
4 /Subtype /Widget /DA (/.AppleSystemUIFont 13 Tf 0 g) /MK 8 0 R /C [ 0 ]
/AP 9 0 R /V /Off /M (D:20250330154918Z00'00') /FT /Btn /Type /Annot /Ff 65536
>>
endobj
9 0 obj
<< /N 10 0 R >>
endobj
8 0 obj
<< /BG [ 0.75 ] >>
endobj
10 0 obj
<< /Filter /FlateDecode /Type /XObject /Subtype /Form /FormType 1 /BBox [0 0 100 100]
/Resources 11 0 R /Length 170 >>
stream
x }ê1 Ç0 Öw~≈ ahÈ KÈ
q1q0\‚`ú Ÿ¿ 8¯Ôm% u0óª‰.Ô{yπ åP°H-}ª‡à y3 ¸ %≠¡‰ %› g¨$•µMVXø‡Hé†Ö ”î“¿˜® BI•L ˆ†b A pü‰Ã @ÓpB∫ †æœs ãÙ:d8Éwÿr»/}” €∂I÷Bõ B;'+gm Ô˝„ mÙ~ L*>•
endstream
endobj
On closing the PDF document, the assigned value for the push button’s caption is not written to the file and is lost.
Observation 2:
On reopening the PDF document, and assigning a new value for the already-created push button’s caption, a key-value pair for the caption is again correctly added to the PDFAnnotation appearance characteristics dictionary.
On saving/writing to the PDF file, this time, the caption key-value pair in the appearance characteristics dictionary is correctly written/saved to the PDF document file.
Resulting PDF markup:
6 0 obj
<< /Border [ 0 0 0 ] /Rect [ 256 299.8977 356 399.8977 ] /T (button23) /F
4 /BS 8 0 R /Subtype /Widget /DA (/.AppleSystemUIFont 13 Tf 0 g) /MK 9 0 R
/C [ 0 ] /AP 10 0 R /V /Off /M (D:20250330154918Z00'00') /FT /Btn /Type /Annot
/Ff 65536 >>
endobj
10 0 obj
<< /N 11 0 R >>
endobj
9 0 obj
<< /BG [ 0.75 ] /CA (My Button) >>
endobj
8 0 obj
<< /W 0 >>
endobj
11 0 obj
<< /Filter /FlateDecode /Type /XObject /Subtype /Form /FormType 1 /BBox [0 0 100 100]
/Resources 12 0 R /Length 163 >>
stream
x uè1 ¬@ Ö˜˛ä7∂√]ì´◊Î≠ ¡A 8à”a∑Vj·ø˜jë™ !ÅÑ|y/=ˆËA1òʺ]pDá|=0¬“Œb ø+Õ gùf2E≤∞Ê≈N` û·Xm©-BãZ†H Ÿ
¿≈ºPÄ= Ø míãp •¡ ÈÓÅ˙>é “kó· Ÿb#—¬ Ûã¶2∂Ñ2fiÎ ;óDÌiÓ?ü>LÁûÊy;}
endstream
endobj
Impact on User Experience:
Push button captions may not be properly saved to the PDF document’s file. This may result in an application redrawing a push button without a caption/label. More so, an application that uses the caption value to “read” a button’s label (e.g., for accessibility purposes) will not be able to do so.
We've seen a spike in crashes on iOS 18.4 across both iPhone & iPad. We can't reproduce it, but it looks like it happens when the app goes into the background.
Crash Log
I set UIToolbar and UIBarButtonItem to UITextField placed on Xib, but when I run it on iOS18 iPad, the following error is output to Xcode Console, and UIPickerView set to UITextField.inputView is not displayed.
Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored. Please fix this problem.
If you want to see the backtrace, please set CG_NUMERICS_SHOW_BACKTRACE environmental variable.
Backtrace:
<CGPathAddLineToPoint+71>
<+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadii:segments:smoothPillShapes:clampCornerRadii:]
<+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadius:segments:]+175>
<+[UIBezierPath _roundedRectBezierPath:withRoundedCorners:cornerRadius:segments:legacyCorners:]+338>
<-[_UITextMagnifiedLoupeView layoutSubviews]+2233>
<__56-[_UITextMagnifiedLoupeView _updateCloseLoupeAnimation:]_block_invoke+89>
<+[UIView(UIViewAnimationWithBlocksPrivate) _modifyAnimationsWithPreferredFrameRateRange:updateReason:animations:]+166>
<block_destroy_helper.269+92>
<block_destroy_helper.269+92>
<__swift_instantiateConcreteTypeFromMangledName+94289>
<block_destroy_helper.269+126>
<+[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:anima
<block_destroy_helper.269+6763>
<block_destroy_helper.269+10907>
<-[_UITextMagnifiedLoupeView _updateCloseLoupeAnimation:]+389>
<-[_UITextMagnifiedLoupeView setVisible:animated:completion:]+256>
<-[UITextLoupeSession _invalidateAnimated:]+329>
<-[UITextRefinementTouchBehavior textLoupeInteraction:gestureChangedWithState:location:translation:velocity:
<-[UITextRefinementInteraction loupeGestureWithState:location:translation:velocity:modifierFlags:shouldCanc
<-[UITextRefinementInteraction loupeGesture:]+701>
<-[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:]+71>
<_UIGestureRecognizerSendTargetActions+100>
<_UIGestureRecognizerSendActions+306>
<-[UIGestureRecognizer _updateGestureForActiveEvents]+704>
<_UIGestureEnvironmentUpdate+3892>
<-[UIGestureEnvironment _updateForEvent:window:]+847>
<-[UIWindow sendEvent:]+4937>
<-[UIApplication sendEvent:]+525>
<__dispatchPreprocessedEventFromEventQueue+1436>
<__processEventQueue+8610>
<updateCycleEntry+151>
<_UIUpdateSequenceRun+55>
<schedulerStepScheduledMainSection+165>
<runloopSourceCallback+68>
<__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__+17>
<__CFRunLoopDoSource0+157>
<__CFRunLoopDoSources0+293>
<__CFRunLoopRun+960>
<CFRunLoopRunSpecific+550>
<GSEventRunModal+137>
<-[UIApplication _run]+875>
<UIApplicationMain+123>
<__debug_main_executable_dylib_entry_point+63>
10d702478 204e57345
Type: Error | Timestamp: 2025-03-09 00:22:46.121407+09:00 | Process: FurusatoLocalCurrency | Library: CoreGraphics | Subsystem: com.apple.coregraphics | Category: Unknown process name | TID: 0x5c360
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSAutoresizingMaskLayoutConstraint:0x600002202a30 h=--& v=--& _UIToolbarContentView:0x7fc2c6a5b8f0.width == 0 (active)>",
"<NSLayoutConstraint:0x600002175e00 H:|-(0)-[_UIButtonBarStackView:0x7fc2c6817b10] (active, names: '|':_UIToolbarContentView:0x7fc2c6a5b8f0 )>",
"<NSLayoutConstraint:0x600002175e50 H:[_UIButtonBarStackView:0x7fc2c6817b10]-(0)-| (active, names: '|':_UIToolbarContentView:0x7fc2c6a5b8f0 )>",
"<NSLayoutConstraint:0x6000022019f0 'TB_Leading_Leading' H:|-(8)-[_UIModernBarButton:0x7fc2a5aa8920] (active, names: '|':_UIButtonBarButton:0x7fc2a5aa84d0 )>",
"<NSLayoutConstraint:0x600002201a40 'TB_Trailing_Trailing' H:[_UIModernBarButton:0x7fc2a5aa8920]-(0)-| (active, names: '|':_UIButtonBarButton:0x7fc2a5aa84d0 )>",
"<NSLayoutConstraint:0x600002201e50 'UISV-canvas-connection' UILayoutGuide:0x600003b7d420'UIViewLayoutMarginsGuide'.leading == _UIButtonBarButton:0x7fc2f57117f0.leading (active)>",
"<NSLayoutConstraint:0x600002201ea0 'UISV-canvas-connection' UILayoutGuide:0x600003b7d420'UIViewLayoutMarginsGuide'.trailing == UIView:0x7fc2a5aac8e0.trailing (active)>",
"<NSLayoutConstraint:0x6000022021c0 'UISV-spacing' H:[_UIButtonBarButton:0x7fc2f57117f0]-(0)-[UIView:0x7fc2a5aa8330] (active)>",
"<NSLayoutConstraint:0x600002202210 'UISV-spacing' H:[UIView:0x7fc2a5aa8330]-(0)-[_UIButtonBarButton:0x7fc2a5aa84d0] (active)>",
"<NSLayoutConstraint:0x600002202260 'UISV-spacing' H:[_UIButtonBarButton:0x7fc2a5aa84d0]-(0)-[UIView:0x7fc2a5aac8e0] (active)>",
"<NSLayoutConstraint:0x600002176f30 'UIView-leftMargin-guide-constraint' H:|-(0)-[UILayoutGuide:0x600003b7d420'UIViewLayoutMarginsGuide'](LTR) (active, names: '|':_UIButtonBarStackView:0x7fc2c6817b10 )>",
"<NSLayoutConstraint:0x600002176e40 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x600003b7d420'UIViewLayoutMarginsGuide']-(0)-|(LTR) (active, names: '|':_UIButtonBarStackView:0x7fc2c6817b10 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600002201a40 'TB_Trailing_Trailing' H:[_UIModernBarButton:0x7fc2a5aa8920]-(0)-| (active, names: '|':_UIButtonBarButton:0x7fc2a5aa84d0 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
When we place a Button inside a ScrollView , the fade animation of the button is delayed, so most users won't see it I think.
You can see this in the trivial example
struct ContentView: View {
var body: some View {
ScrollView {
Button {
// empty
} label: {
Text("Fade animation test")
}
}
}
}
Is there any way to opt out of this behavior? In UIKit, this was also the default behavior, but you could always change it by overriding touchesShouldCancel method.
I think I can probably do that by rewriting an animation completely with some custom ButtonStyle or by rewriting a Button component completely, but it doesn't seem like a good solution to me, as I want the native look and feel (in case of button animation it is pretty easy to mimic though).
And also for some components, like lists, Apple has already implemented the correct behavior by themselves somehow.
Why is there no option as a CarPlay developer to enable the creation of an App to track and enter your car's maintenance records? I know the pat reply would be Apple doesn't want you to do this while car is in motion. But I would normally do this while parked at the dealership or other service provider no?