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.

All subtopics
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Created

Issue: Chart Scroll Not Working in iOS 18 with Chart Overlay Tap Gesture
Summary I have a SwiftUI Chart that worked correctly in iOS 17, allowing both horizontal scrolling and tap gesture selection. However, in iOS 18, the same exact chart will not allow for both tap gestures and scrolling to work -- it's either we allow scrolling or we allow tap gestures but not both. We have tried everything to try to circumvent this issue but have had to resort to old methods of creating the chart. This is an issue that has negatively impacted our customers as well. Again, the charts were working fine on iOS 17, but on iOS 18 the chart scroll + tap gesture capability is not working. Expected Behavior (iOS 17) Users can scroll horizontally through the chart. Users can tap on data points to highlight them. The selected data point updates when tapped. Observed Behavior (iOS 18) The chart no longer scrolls when chartOverlay with the Tap Gesture is applied. Tap selection still works as expected. Code Snippet Below is the working implementation from iOS 17: private var iOS17ChartView: some View { Chart { RectangleMark( yStart: .value(String(firstLevelAlertBand), firstLevelAlertBand), yEnd: .value("100", 100) ) .foregroundStyle(Theme.Colors.green.opacity(0.15)) RectangleMark( yStart: .value(String(secondLevelAlertBand), secondLevelAlertBand), yEnd: .value(String(firstLevelAlertBand), firstLevelAlertBand) ) .foregroundStyle(Theme.Colors.orange.opacity(0.15)) RectangleMark( yStart: .value("0", 0), yEnd: .value(String(secondLevelAlertBand), secondLevelAlertBand) ) .foregroundStyle(Theme.Colors.red.opacity(0.15)) ForEach(telemetryData, id: \.timestamp) { entry in if let utcDate = dateFormatter.date(from: entry.timestamp) { let localDate = convertToUserTimeZone(date: utcDate) let tankLevel = entry.tankLevel ?? 0 LineMark( x: .value("Date", localDate), y: .value("Tank Level", tankLevel) ) .foregroundStyle(statusColor) AreaMark( x: .value("Date", localDate), y: .value("Tank Level", tankLevel) ) .foregroundStyle(statusColor.opacity(0.50)) PointMark( x: .value("Date", localDate), y: .value("Tank Level", tankLevel) ) .foregroundStyle(selectedDataPoint?.date == localDate ? Theme.Colors.primaryColor : statusColor) .symbolSize(selectedDataPoint?.date == localDate ? 120 : 80) PointMark( x: .value("Date", localDate), y: .value("Tank Level", tankLevel) ) //.foregroundStyle(.white).symbolSize(10) .foregroundStyle(Theme.Colors.white(colorScheme: colorScheme)) .symbolSize(12) } } } .chartXScale(domain: (firstTimestamp ?? Date())...(latestTimestamp ?? Date())) .chartXVisibleDomain(length: visibleDomainSize) .chartScrollableAxes(.horizontal) .chartScrollPosition(x: $chartScrollPositionX) .chartXAxis { AxisMarks(values: .stride(by: xAxisStrideUnit, count: xAxisCount())) { value in if let utcDate = value.as(Date.self) { let localDate = convertToUserTimeZone(date: utcDate) let formatStyle = self.getFormatStyle(for: interval) AxisValueLabel { Text(localDate, format: formatStyle) .font(Theme.Fonts.poppinsRegularExtraSmall) .foregroundStyle(Theme.Colors.black(colorScheme: colorScheme)) } AxisTick() .foregroundStyle(Theme.Colors.black(colorScheme: colorScheme).opacity(1)) } } } .chartOverlay { proxy in GeometryReader { geometry in Rectangle().fill(Color.clear).contentShape(Rectangle()) .onTapGesture { location in let xPosition = location.x - geometry[proxy.plotAreaFrame].origin.x // Use proxy to get the x-axis value at the tapped position if let selectedDate: Date = proxy.value(atX: xPosition) { if let closestEntry = telemetryData.min(by: { abs(dateFormatter.date(from: $0.timestamp)!.timeIntervalSince1970 - selectedDate.timeIntervalSince1970) < abs(dateFormatter.date(from: $1.timestamp)!.timeIntervalSince1970 - selectedDate.timeIntervalSince1970) }) { selectedDataPoint = (convertToUserTimeZone(date: dateFormatter.date(from: closestEntry.timestamp)!), closestEntry.tankLevel ?? 0) if let dateXPos = proxy.position(forX: convertToUserTimeZone(date: dateFormatter.date(from: closestEntry.timestamp)!)), let tankLevelYPos = proxy.position(forY: closestEntry.tankLevel ?? 0) { // Offset the x-position based on the scroll position let adjustedXPos = dateXPos - proxy.position(forX: chartScrollPositionX)! withAnimation(.spring()) { selectedPointLocation = CGPoint(x: adjustedXPos, y: tankLevelYPos - 60) // Offset popup above the point showPopup = true } } } } } } .onChange(of: chartScrollPositionX) { newValue in // Dynamically update the popup position when scroll changes if let selectedDataPoint = selectedDataPoint { if let dateXPos = proxy.position(forX: selectedDataPoint.date) { let adjustedXPos = dateXPos - proxy.position(forX: chartScrollPositionX)! selectedPointLocation.x = adjustedXPos } } } } } Please help! Nick
1
1
647
Feb ’25
.presentationDetents not working on iOS 17
Hello, I have the following code: .sheet(isPresented: $viewModel.isExerciseSelected) { ExerciseEditSheetView(viewModel: viewModel) .presentationDetents([.fraction(0.4)]) } This code correctly sizes the sheet on my iOS 18 simulator, but does not work on my iOS 17 simulator as well as my actual phone running iOS 17. Instead the sheet always fullscreens. Although its not the end of the world it is pretty annoying. Is there anything I'm missing? Thanks in advance.
Topic: UI Frameworks SubTopic: SwiftUI
2
0
324
Feb ’25
Since iOS 18.3, icons are no longer generated correctly with QLThumbnailGenerator
Since iOS 18.3, icons are no longer generated correctly with QLThumbnailGenerator. No error is returned either. But this error message now appears in the console: Error returned from iconservicesagent image request: <ISTypeIcon: 0x3010f91a0>,Type: com.adobe.pdf - <ISImageDescriptor: 0x302f188c0> - (36.00, 36.00)@3x v:1 l:5 a:0:0:0:0 t:() b:0 s:2 ps:0 digest: B19540FD-0449-3E89-AC50-38F92F9760FE error: Error Domain=NSOSStatusErrorDomain Code=-609 "Client is disallowed from making such an icon request" UserInfo={NSLocalizedDescription=Client is disallowed from making such an icon request} Does anyone know this error? Is there a workaround? Are there new permissions to consider? Here is the code how icons are generated: let request = QLThumbnailGenerator.Request(fileAt: url, size: size, scale: scale, representationTypes: self.thumbnailType) request.iconMode = true let generator = QLThumbnailGenerator.shared generator.generateRepresentations(for: request) { [weak self] thumbnail, _, error in }
16
5
1.7k
Feb ’25
NSLayoutManager returning inconsistent values for a glyph's text container and its line fragment rect
TLDR: NSLayoutManager's textContainer(forGlyphAt:effectiveRange:) and lineFragmentRect(forGlyphRange:effectiveRange:) are returning inconsistent results. Context: I'm developing a word processing app that paginates from an NSTextStorage using NSLayoutManager. My app uses a text attribute (.columnType) to paginate sub-ranges of the text at a time, ensuring that each columnRange gets a container (or series of containers across page breaks) to fit. This is to support both multi-column and standard full-page-width content. After any user edit, I update pagination data in my Paginator model class. I calcuate frames/sizes for the views/containers, along with what superview they belong to (page). The UI updates accordingly. In order to determine whether the columnRange has overflowed from a container due to a page break OR whether the range of text hasn't overflowed its container and is actually using less space than available and should be sized down, I call both: layoutManager.textContainer(forGlyphAt: lastGlyphOfColumn, effectiveRange: &actualGlyphRangeInContainer)` // and `layoutManager.lineFragmentRect(forGlyphAt: lastGlyphOfColumn, effectiveRange: nil) Apple Documentation notes that both these calls force glyph generation and layout. As I'm in early development, I have not set non-contiguous layout. So these should be causing full layout, assuring accurate return values. Or so I'd hoped. This does work fine in many cases. I edit. Pagination works. But then I'll encounter UI-breaking inconsistent returns from these two calls. By inconsistent, I mean that the second call returns a line fragment rect that is in the container coordinates of A DIFFERENT container than the container returned by the first call. To be specific, the line fragment rect seems to be in the coordinates of the container that comes next in layoutManager.textContainers. Example Code: if !layoutManager.textContainers.indices.contains(i) { containerToUse = createTextContainer(with: availableSize) layoutManager.addTextContainer(containerToUse) } else { // We have a container already but it may be // the wrong size. containerToUse = layoutManager.textContainers[i] if containerToUse.size.width != availableSize.width { // Mandatory that we resize if we don't have // a matching width. Height resizing is not // mandatory and requires a layout check below. containerToUse.size = availableSize } } let glyphRange = layoutManager.glyphRange(forCharacterRange: remainingColumnRange, actualCharacterRange: nil) let lastGlyphOfColumn = NSMaxRange(glyphRange) - 1 var containerForLastGlyphOfColumn = layoutManager.textContainer(forGlyphAt: lastGlyphOfColumn, effectiveRange: &actualGlyphRangeInContainer) if containerForLastGlyphOfColumn != containerToUse && containerToUse.size.height < availableSize.height { // If we are here, we overflowed the container, // BUT the container we overflowed didn't use // the maximum remaining page space (this // means it was a pre-existing container that // needs to be sized up and checked once more). // NOTE RE: THE BUG: // at this point, prints show... // containerToUse.size.height // =628 // availableSize.height // =648 containerToUse.size = availableSize containerForLastGlyphOfColumn = layoutManager.textContainer(forGlyphAt: lastGlyphOfColumn, effectiveRange: &actualGlyphRangeInContainer) } // We now check again, knowing that the container we // are testing flow into is the max size it can be. if containerForLastGlyphOfColumn != containerToUse { // If we are here, we have overflowed the // container, so containerToUse size SHOULD be // final/accurate, since it is fully used. actualCharRangeInContainer = layoutManager.characterRange(forGlyphRange: actualGlyphRangeInContainer, actualGlyphRange: nil) // Start of overflow range is the first character // in the container that was overflowed into. let overflowLoc = actualCharRangeInContainer.location remainingColumnRange = NSRange(location: overflowLoc, length: remainingColumnRange.length - overflowLoc) // Update page count as we have broken to a new page currentPage += 1 } else { // If we are here, we have NOT overflowed // from the container. BUT... // THE BUG: // ***** HERE IS THE BUG! ***** lineFragmentRectForLastChar = layoutManager.lineFragmentRect(forGlyphAt: lastGlyphOfColumn, effectiveRange: nil) let usedHeight = lineFragmentRectForLastChar.maxY // BUG: ^The lines of code above return a // fragment rect that is in the coordinates // of the WRONG text container. Prints show: // usedHeight // =14 // usedHeight shouldn't be just 14 if this is // the SAME container that, when it was 628 // high, resulted in text overflowing. // Therefore, the line fragment here seems // to be in the coordinates of the ENSUING // container that we overflowed INTO, but // that shouldn't be possible, since we're in // a closure for which we know: // // containerForLastGlyphOfColumn == containerToUse // // If the last glyph container is the container // we just had to size UP, why does the final // glyph line fragment rect have a maxY of 14!? // Including ensuing code below only for context. if usedHeight < containerToUse.size.height { // Adjust container size down to usedRect containerToUse.size = CGSize(width: containerToUse.size.width, height: usedHeight) } else if usedHeight == availableSize.height { // We didn't force break to a new page BUT // we've used exactly the height of our page // to layout this column range, so need to // break to a new page for any ensuing text // columns. currentPage += 1 } else if usedHeight > containerToUse.size.height { // We should have caught this earlier. Text // has overflowed, but this should've been // caught when we checked // containerForLastGlyphOfColumn != // containerToUse. // // Note: this error has never thrown. throw PaginationError.unknownError("Oops.") } } Per my comments in the code block above, I don't understand why the very same text container that just overflowed and so had to be sized up from 628 to 648 in order to try to fit a glyph would now report that same glyph as both being IN that same container and having a line fragment rect with a maxY of just 14. A glyph couldn't fit in a container when it was 628 high, but if I size it up to 648, it only needs 14? There's something very weird going on here. Working with NSLayoutManager is a bit of a nightmare given the unclear documentation. Any help or insight here would be massively, massively appreciated.
2
0
554
Feb ’25
Simulating key press event to type text in UITextField
in iOS, user can set focus on UItextField and tapping a key in the virtual keyboard updates the text in the textfield. This user action causes the relevant delegates of UITextFieldDelegate to get invoked, i.e the handlers associated with action of user entering some text in the textfield. I m trying to simulate this user action where I am trying to do this programatically. I want to simulate it in a way such that all the handlers/listeners which otherwise would have been invoked as a result of user typing in the textfield should also get invoked now when i am trying to do it programatically. I have a specific usecase of this in my application. Below is how I m performing this simulation. I m manually updating the text field associated(UITextField.text) and updating its value. And then I m invoking the delegate manually as textField.delegate?.textField?(textField, shouldChangeCharactersIn: nsRange, replacementString: replacementString) I wanted to know If this is the right way to do this. Is there something better available that can be used, such that simulation has the same affect as the user performing the update?
Topic: UI Frameworks SubTopic: UIKit Tags:
4
0
405
Feb ’25
Swift Charts: How to prevent scroll position jump when loading more data dynamically
I'm implementing infinite scrolling with Swift Charts where additional historical data loads when scrolling near the beginning of the dataset. However, when new data is loaded, the chart's scroll position jumps unexpectedly. Current behavior: Initially loads 10 data points, displaying the latest 5 When scrolling backwards with only 3 points remaining off-screen, triggers loading of 10 more historical points After loading, the scroll position jumps to the 3rd position of the new dataset instead of maintaining the current view Expected behavior: Scroll position should remain stable when new data is loaded User's current view should not change during data loading Here's my implementation logic using some mock data: import SwiftUI import Charts struct DataPoint: Identifiable { let id = UUID() let date: Date let value: Double } class ChartViewModel: ObservableObject { @Published var dataPoints: [DataPoint] = [] private var isLoading = false init() { loadMoreData() } func loadMoreData() { guard !isLoading else { return } isLoading = true let newData = self.generateDataPoints( endDate: self.dataPoints.first?.date ?? Date(), count: 10 ) self.dataPoints.insert(contentsOf: newData, at: 0) self.isLoading = false print("\(dataPoints.count) data points.") } private func generateDataPoints(endDate: Date, count: Int) -> [DataPoint] { var points: [DataPoint] = [] let calendar = Calendar.current for i in 0..<count { let date = calendar.date( byAdding: .day, value: -i, to: endDate ) ?? endDate let value = Double.random(in: 0...100) points.append(DataPoint(date: date, value: value)) } return points.sorted { $0.date < $1.date } } } struct ScrollableChart: View { @StateObject private var viewModel = ChartViewModel() @State private var scrollPosition: Date @State private var scrollDebounceTask: Task<Void, Never>? init() { self.scrollPosition = .now.addingTimeInterval(-4*24*3600) } var body: some View { Chart(viewModel.dataPoints) { point in BarMark( x: .value("Time", point.date, unit: .day), y: .value("Value", point.value) ) } .chartScrollableAxes(.horizontal) .chartXVisibleDomain(length: 5 * 24 * 3600) .chartScrollPosition(x: $scrollPosition) .chartXScale(domain: .automatic(includesZero: false)) .frame(height: 300) .onChange(of: scrollPosition) { oldPosition, newPosition in scrollDebounceTask?.cancel() scrollDebounceTask = Task { try? await Task.sleep(for: .milliseconds(300)) if !Task.isCancelled { checkAndLoadMoreData(currentPosition: newPosition) } } } } private func checkAndLoadMoreData(currentPosition: Date?) { guard let currentPosition, let earliestDataPoint = viewModel.dataPoints.first?.date else { return } let timeInterval = currentPosition.timeIntervalSince(earliestDataPoint) if timeInterval <= 3 * 24 * 3600 { viewModel.loadMoreData() } } } I attempted to compensate for this jump by adding: scrollPosition = scrollPosition.addingTimeInterval(10 * 24 * 3600) after viewModel.loadMoreData(). However, this caused the chart to jump in the opposite direction by 10 days, rather than maintaining the current position. What's the problem with my code and how to fix it?
6
0
607
Feb ’25
VisionOS custom hover effect and click sound
I have created a custom hover effect per this WWDC video and many other examples on the Net: https://developer.apple.com/videos/play/wwdc2024/10152/ I can get the button to expand when looked at within a VisionOS device and it will invoke a tap event when tapped but there is no click sound like a normal SwiftUI button does in VisionOS! I can't for the life of me figure out why. Any help would be appreciated!
2
0
314
Feb ’25
Scroll to Top gesture breaks when setting List or ScrollView background
When a ScrollView or List is nested in a TabView, you can press on the tab button and the scroll view will scroll to top. import SwiftUI struct SwiftUIView: View { let items = (1...100).map { "Item \($0)" } var body: some View { TabView { Tab("home", systemImage: "house") { ScrollView { ForEach(items, id: \.self) { item in Text(item) .frame(maxWidth: .infinity, alignment: .center) } } } } } } #Preview { SwiftUIView() } But if we add a background to the ScrollView, the scroll to top gesture breaks. import SwiftUI struct SwiftUIView: View { let items = (1...100).map { "Item \($0)" } var body: some View { TabView { Tab("home", systemImage: "house") { ScrollView { ForEach(items, id: \.self) { item in Text(item) .frame(maxWidth: .infinity, alignment: .center) } } // Set background on ScrollView. .background(Color.red) } } } } #Preview { SwiftUIView() } I made a similar post on StackOverflow, but haven't been able to find a proper solution. This feels like a bug of some sort in SwiftUI.
1
2
285
Feb ’25
Control Widget SF image cannot stably display
I'm working on the control widget which should display the SF image on the UI, but I have found that it cannot be displayed stably. I have three ExampleControlWidget which is about the type egA egB and egC, it should all be showed but now they only show the text and placeholder. I'm aware of the images should be SF image and I can see them to show perfectly sometimes, but in other time it is just failed. This's really confused me, can anyone help me out? public enum ControlWidgetType: Sendable { case egA case egB case egC public var imageName: String { switch self { case .egA: return "egA" case .egB: return "egB" case .egC: return "egC" } } } struct ExampleControlWidget: ControlWidget { var body: some ControlWidgetConfiguration { AppIntentControlConfiguration( kind: kind, provider: Provider() ) { example in ControlWidgetToggle( example.name, isOn: example.state.isOn, action: ExampleControlWidgetIntent(id: example.id), valueLabel: { isOn in ExampleControlWidgetView( statusText: isOn ? Localization.on.text : Localization.off.text, bundle: bundle, widgetType: .egA //or .egB .egC ) .symbolEffect(.pulse) } ) .disabled(example.state.isDisabled) } .promptsForUserConfiguration() } } public struct ExampleControlWidgetView: View { private let statusText: String private let bundle: Bundle private var widgetType: ControlWidgetType = .egA public init(statusText: String, bundle: Bundle, widgetType: ControlWidgetType) { self.statusText = statusText self.bundle = bundle self.widgetType = widgetType } public var body: some View { Label( statusText, image: .init( name: widgetType.imageName, // the SF Symbol image id bundled in the Widget extension bundle: bundle ) ) } } This is the normal display: These are the display that do not show properly: The results has no rules at all, I have tried to completely uninstall the APP and reinstall but the result is same.
3
0
388
Feb ’25
UITextView crash on iOS 18.4 beta
UITextView crash when setting attributed text that contains substring ffi and attributedText contains NSFontAttributeName, NSForegroundColorAttributeName Reproducible case: UITextView *textView = [[UITextView alloc] init]; textView.attributedText = [[NSAttributedString alloc] initWithString:@"ffi" attributes:@{ NSParagraphStyleAttributeName: [self createParagraphOfLineHeight:20], NSFontAttributeName: [UIFont systemFontOfSize:fontSize weight:UIFontWeightRegular], NSForegroundColorAttributeName: UIColor.black }];
Topic: UI Frameworks SubTopic: UIKit Tags:
9
2
2.2k
Mar ’25
SwiftUI Table performance issue
I found the Table with Toggle will have performance issue when the data is large. I can reproduce it in Apple demo: https://developer.apple.com/documentation/swiftui/building_a_great_mac_app_with_swiftui Replace with a large mock data, for example database.json Try to scroll the table, it's not smooth. I found if I delete the Toggle, the performance be good. TableColumn("Favorite", value: \.favorite, comparator: BoolComparator()) { plant in Toggle("Favorite", isOn: $garden[plant.id].favorite) .labelsHidden() } Is this bug in SwiftUI? Any workaround? My Mac is Intel, not sure it can repro on Apple Silicon
2
0
507
Mar ’25
AppIntent perform method not called.
We have a widget bundle with multiple widgets. I'm adding a widget that is interactive (iOS 17 and higher). Our widget code is in a static library that gets linked into the widget extension target in our main app Xcode project. I have SwiftUI buttons constructed with the intent constructor in our UI See https://developer.apple.com/documentation/swiftui/button/init(intent:label:) When I press the button the timeline refreshes (conforming to TimelineProvider) but the perform method doesn't seem to be called. I've seen multiple pieces of advice and none of them seem to work. I've tried on a physical device and a simulator. I've tried adding an AppIntentsPackage. I've tried including the AppIntent code in the app and the widget. I've tried setting the openAppWhenRun to true and false and not setting it at all. I've tried simplifying the intent to just printing out a line to the console and returning a result. At this point I have no idea how to debug this and I don't know what else to try. I appreciate any helpful advice at this point.
4
0
364
Mar ’25
SwiftUI Preview Runtime linking failure
I'm using GoogleMaps in my project. Legacy preview works well but new preview (Xcode 16.3.1 beta) produces error. It doesn't seem to find Googlemaps.a. == PREVIEW UPDATE ERROR: FailedToLaunchAppError: Failed to launch *** ================================== | [Remote] JITError | | ================================== | | | [Remote] CouldNotLoadInputStaticArchiveFile: Could not load static archive during preview: /Users/xxx/Library/Developer/Xcode/DerivedData/BOA-eiluspltxasszsfkpqrnnsxsjhth/Build/Products/Debug_BOA_Inhouse-iphonesimulator/GoogleMaps.a | | | | path: /Users/xxx/Library/Developer/Xcode/DerivedData/BOA-eiluspltxasszsfkpqrnnsxsjhth/Build/Products/Debug_BOA_Inhouse-iphonesimulator/GoogleMaps.a | | | | ================================== | | | | | [Remote] XOJITError | | | | | | XOJITError: arm64 slice of /Users/xxx/Library/Developer/Xcode/DerivedData/BOA-eiluspltxasszsfkpqrnnsxsjhth/Build/Products/Debug_BOA_Inhouse-iphonesimulator/GoogleMaps.a does not contain an archive
12
0
1.6k
Mar ’25
[StoreKit] Runtime warning with manageSubscriptionsSheet and ObservableObject
The following runtime warning is emitted by Xcode when using the manageSubscriptionsSheet with an ObservableObject: \ContentViewModel.isPresented is isolated to the main actor. Accessing it via Binding from a different actor will cause undefined behaviors, and potential data races; This warning will become a runtime crash in a future version of SwiftUI. Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates. This minimal sample project reproduces the issue: class ContentViewModel: ObservableObject { @Published var isPresented = false func didTapButton() { self.isPresented = true } } struct ContentView: View { @ObservedObject var viewModel: ContentViewModel var body: some View { Button("Tap me") { self.viewModel.didTapButton() } .manageSubscriptionsSheet(isPresented: self.$viewModel.isPresented) } } Reproduced on: Xcode 16.2 Xcode 16.3 beta both with a simulator and a real device. This doesn't happen when using @Observable.
1
1
273
Mar ’25
iOS 18.4 Beta: On iPhones which support Dynamic Island, the AppDelegate method applicationDidBecomeActive() takes longer to be called.
When testing with iOS 18.4 Beta on iPhones which support Dynamic Island, after doing a Face ID authentication, the amount of time it takes before the AppDelegate method applicationDidBecomeActive() is called takes longer than iPhones that do not support Dynamic Island. The time it takes is about double, 1.2 seconds vs 2.5 seconds on average. This does not occur with versions before 18.4 Beta. Anyone else seeing this?
Topic: UI Frameworks SubTopic: UIKit
2
3
381
Mar ’25
NSTextLineFragment crash - how to debug
We have crash reports as shown below that we haven't yet been able to repro and could use some help deubgging. My guess is that the app is giving a label or text view an attributed string with an invalid attribute range, but attributed strings are used in many places throughout the app, and I don't know an efficient way to track this down. I'm posting the stack trace here in hopes that someone more familiar with the internals of the system frameworks mentioned will be able to provide a clue to help narrow where I should look. Fatal Exception: NSRangeException NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds 0 CoreFoundation 0x2d5fc __exceptionPreprocess 1 libobjc.A.dylib 0x31244 objc_exception_throw 2 Foundation 0x47130 blockForLocation 3 UIFoundation 0x2589c -[NSTextLineFragment _defaultRenderingAttributesAtCharacterIndex:effectiveRange:] 4 UIFoundation 0x25778 __53-[NSTextLineFragment initWithAttributedString:range:]_block_invoke 5 CoreText 0x58964 TLine::DrawGlyphsWithAttributeOverrides(TLineDrawContext const&, __CFDictionary const* (long, CFRange*) block_pointer, TDecoratorObserver*) const 6 CoreText 0x58400 CTLineDrawWithAttributeOverrides 7 UIFoundation 0x25320 _NSCoreTypesetterRenderLine 8 UIFoundation 0x24b10 -[NSTextLineFragment drawAtPoint:graphicsContext:] 9 UIFoundation 0x3e634 -[NSTextLineFragment drawAtPoint:inContext:] 10 UIFoundation 0x3e450 -[NSTextLayoutFragment drawAtPoint:inContext:] 11 UIKitCore 0x3e3098 __38-[_UITextLayoutFragmentView drawRect:]_block_invoke 12 UIKitCore 0x3e31cc _UITextCanvasDrawWithFadedEdgesInContext 13 UIKitCore 0x3e3040 -[_UITextLayoutFragmentView drawRect:] 14 UIKitCore 0xd7a98 -[UIView(CALayerDelegate) drawLayer:inContext:] 15 QuartzCore 0x109340 CABackingStoreUpdate_ 16 QuartzCore 0x109224 invocation function for block in CA::Layer::display_() 17 QuartzCore 0x917f0 -[CALayer _display] 18 QuartzCore 0x90130 CA::Layer::layout_and_display_if_needed(CA::Transaction*) 19 QuartzCore 0xe50c4 CA::Context::commit_transaction(CA::Transaction*, double, double*) 20 QuartzCore 0x5bd8c CA::Transaction::commit() 21 UIKitCore 0x9f3f0 _UIApplicationFlushCATransaction 22 UIKitCore 0x9c89c __setupUpdateSequence_block_invoke_2 23 UIKitCore 0x9c710 _UIUpdateSequenceRun 24 UIKitCore 0x9f040 schedulerStepScheduledMainSection 25 UIKitCore 0x9cc5c runloopSourceCallback 26 CoreFoundation 0x73f4c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ 27 CoreFoundation 0x73ee0 __CFRunLoopDoSource0 28 CoreFoundation 0x76b40 __CFRunLoopDoSources0 29 CoreFoundation 0x75d3c __CFRunLoopRun 30 CoreFoundation 0xc8284 CFRunLoopRunSpecific 31 GraphicsServices 0x14c0 GSEventRunModal 32 UIKitCore 0x3ee674 -[UIApplication _run] 33 UIKitCore 0x14e88 UIApplicationMain also filed as FB16905066
6
1
535
Mar ’25
Collection view with self-sizing cells with SwiftUI content
I am trying to make a collection view with self-sizing cells that adapt to SwiftUI content. My test platform is macOS, but it should work on iOS all the same. I chose macOS because on macOS, you can resize the window and cause more interesting scenarios with that. My layout intent is fairly simple: a one-column collection view with cells with SwiftUI content, where the collection view cells should adapt to the height of their SwiftUI content. I got it working almost correctly. The one scenario that I don’t have working is window resizing. When the window resizes, the layout and cells should adapt to the content and change their heights. I feel that I am missing something fairly basic. How do I change this project so that the layout works correctly when I change the macOS window width? Example project and video of the behavior: https://gist.github.com/jaanus/66e3d863941ba645c88220b8a22970e1
Topic: UI Frameworks SubTopic: AppKit
1
0
384
Mar ’25
Crash when assigning NSImage to `@objc dynamic var` property
Xcode downloaded a crash report for my app which I don't quite understand. It seems the following line caused the crash: myEntity.image = newImage where myEntity is of type MyEntity: class MyEntity: NSObject, Identifiable { @objc dynamic var image: NSImage! ... } The code is called on the main thread. According to the crash report, thread 0 makes that assignment, and at the same time thread 16 is calling [NSImageView asynchronousPreparation:prepareResultUsingParameters:]. What could cause such a crash? Could I be doing something wrong or is this a bug in macOS? crash.crash
11
0
259
Mar ’25
Issue: Chart Scroll Not Working in iOS 18 with Chart Overlay Tap Gesture
Summary I have a SwiftUI Chart that worked correctly in iOS 17, allowing both horizontal scrolling and tap gesture selection. However, in iOS 18, the same exact chart will not allow for both tap gestures and scrolling to work -- it's either we allow scrolling or we allow tap gestures but not both. We have tried everything to try to circumvent this issue but have had to resort to old methods of creating the chart. This is an issue that has negatively impacted our customers as well. Again, the charts were working fine on iOS 17, but on iOS 18 the chart scroll + tap gesture capability is not working. Expected Behavior (iOS 17) Users can scroll horizontally through the chart. Users can tap on data points to highlight them. The selected data point updates when tapped. Observed Behavior (iOS 18) The chart no longer scrolls when chartOverlay with the Tap Gesture is applied. Tap selection still works as expected. Code Snippet Below is the working implementation from iOS 17: private var iOS17ChartView: some View { Chart { RectangleMark( yStart: .value(String(firstLevelAlertBand), firstLevelAlertBand), yEnd: .value("100", 100) ) .foregroundStyle(Theme.Colors.green.opacity(0.15)) RectangleMark( yStart: .value(String(secondLevelAlertBand), secondLevelAlertBand), yEnd: .value(String(firstLevelAlertBand), firstLevelAlertBand) ) .foregroundStyle(Theme.Colors.orange.opacity(0.15)) RectangleMark( yStart: .value("0", 0), yEnd: .value(String(secondLevelAlertBand), secondLevelAlertBand) ) .foregroundStyle(Theme.Colors.red.opacity(0.15)) ForEach(telemetryData, id: \.timestamp) { entry in if let utcDate = dateFormatter.date(from: entry.timestamp) { let localDate = convertToUserTimeZone(date: utcDate) let tankLevel = entry.tankLevel ?? 0 LineMark( x: .value("Date", localDate), y: .value("Tank Level", tankLevel) ) .foregroundStyle(statusColor) AreaMark( x: .value("Date", localDate), y: .value("Tank Level", tankLevel) ) .foregroundStyle(statusColor.opacity(0.50)) PointMark( x: .value("Date", localDate), y: .value("Tank Level", tankLevel) ) .foregroundStyle(selectedDataPoint?.date == localDate ? Theme.Colors.primaryColor : statusColor) .symbolSize(selectedDataPoint?.date == localDate ? 120 : 80) PointMark( x: .value("Date", localDate), y: .value("Tank Level", tankLevel) ) //.foregroundStyle(.white).symbolSize(10) .foregroundStyle(Theme.Colors.white(colorScheme: colorScheme)) .symbolSize(12) } } } .chartXScale(domain: (firstTimestamp ?? Date())...(latestTimestamp ?? Date())) .chartXVisibleDomain(length: visibleDomainSize) .chartScrollableAxes(.horizontal) .chartScrollPosition(x: $chartScrollPositionX) .chartXAxis { AxisMarks(values: .stride(by: xAxisStrideUnit, count: xAxisCount())) { value in if let utcDate = value.as(Date.self) { let localDate = convertToUserTimeZone(date: utcDate) let formatStyle = self.getFormatStyle(for: interval) AxisValueLabel { Text(localDate, format: formatStyle) .font(Theme.Fonts.poppinsRegularExtraSmall) .foregroundStyle(Theme.Colors.black(colorScheme: colorScheme)) } AxisTick() .foregroundStyle(Theme.Colors.black(colorScheme: colorScheme).opacity(1)) } } } .chartOverlay { proxy in GeometryReader { geometry in Rectangle().fill(Color.clear).contentShape(Rectangle()) .onTapGesture { location in let xPosition = location.x - geometry[proxy.plotAreaFrame].origin.x // Use proxy to get the x-axis value at the tapped position if let selectedDate: Date = proxy.value(atX: xPosition) { if let closestEntry = telemetryData.min(by: { abs(dateFormatter.date(from: $0.timestamp)!.timeIntervalSince1970 - selectedDate.timeIntervalSince1970) < abs(dateFormatter.date(from: $1.timestamp)!.timeIntervalSince1970 - selectedDate.timeIntervalSince1970) }) { selectedDataPoint = (convertToUserTimeZone(date: dateFormatter.date(from: closestEntry.timestamp)!), closestEntry.tankLevel ?? 0) if let dateXPos = proxy.position(forX: convertToUserTimeZone(date: dateFormatter.date(from: closestEntry.timestamp)!)), let tankLevelYPos = proxy.position(forY: closestEntry.tankLevel ?? 0) { // Offset the x-position based on the scroll position let adjustedXPos = dateXPos - proxy.position(forX: chartScrollPositionX)! withAnimation(.spring()) { selectedPointLocation = CGPoint(x: adjustedXPos, y: tankLevelYPos - 60) // Offset popup above the point showPopup = true } } } } } } .onChange(of: chartScrollPositionX) { newValue in // Dynamically update the popup position when scroll changes if let selectedDataPoint = selectedDataPoint { if let dateXPos = proxy.position(forX: selectedDataPoint.date) { let adjustedXPos = dateXPos - proxy.position(forX: chartScrollPositionX)! selectedPointLocation.x = adjustedXPos } } } } } Please help! Nick
Replies
1
Boosts
1
Views
647
Activity
Feb ’25
.presentationDetents not working on iOS 17
Hello, I have the following code: .sheet(isPresented: $viewModel.isExerciseSelected) { ExerciseEditSheetView(viewModel: viewModel) .presentationDetents([.fraction(0.4)]) } This code correctly sizes the sheet on my iOS 18 simulator, but does not work on my iOS 17 simulator as well as my actual phone running iOS 17. Instead the sheet always fullscreens. Although its not the end of the world it is pretty annoying. Is there anything I'm missing? Thanks in advance.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
324
Activity
Feb ’25
Since iOS 18.3, icons are no longer generated correctly with QLThumbnailGenerator
Since iOS 18.3, icons are no longer generated correctly with QLThumbnailGenerator. No error is returned either. But this error message now appears in the console: Error returned from iconservicesagent image request: <ISTypeIcon: 0x3010f91a0>,Type: com.adobe.pdf - <ISImageDescriptor: 0x302f188c0> - (36.00, 36.00)@3x v:1 l:5 a:0:0:0:0 t:() b:0 s:2 ps:0 digest: B19540FD-0449-3E89-AC50-38F92F9760FE error: Error Domain=NSOSStatusErrorDomain Code=-609 "Client is disallowed from making such an icon request" UserInfo={NSLocalizedDescription=Client is disallowed from making such an icon request} Does anyone know this error? Is there a workaround? Are there new permissions to consider? Here is the code how icons are generated: let request = QLThumbnailGenerator.Request(fileAt: url, size: size, scale: scale, representationTypes: self.thumbnailType) request.iconMode = true let generator = QLThumbnailGenerator.shared generator.generateRepresentations(for: request) { [weak self] thumbnail, _, error in }
Replies
16
Boosts
5
Views
1.7k
Activity
Feb ’25
HealthKit heart rate zones
I would like to get user's heart rate zones values in my watchOS app, is there any way to get it from HealthKit? Furthermore, is it possible to display the Apple heart rate zones widget in my watchOS app?
Replies
2
Boosts
0
Views
369
Activity
Feb ’25
NSLayoutManager returning inconsistent values for a glyph's text container and its line fragment rect
TLDR: NSLayoutManager's textContainer(forGlyphAt:effectiveRange:) and lineFragmentRect(forGlyphRange:effectiveRange:) are returning inconsistent results. Context: I'm developing a word processing app that paginates from an NSTextStorage using NSLayoutManager. My app uses a text attribute (.columnType) to paginate sub-ranges of the text at a time, ensuring that each columnRange gets a container (or series of containers across page breaks) to fit. This is to support both multi-column and standard full-page-width content. After any user edit, I update pagination data in my Paginator model class. I calcuate frames/sizes for the views/containers, along with what superview they belong to (page). The UI updates accordingly. In order to determine whether the columnRange has overflowed from a container due to a page break OR whether the range of text hasn't overflowed its container and is actually using less space than available and should be sized down, I call both: layoutManager.textContainer(forGlyphAt: lastGlyphOfColumn, effectiveRange: &actualGlyphRangeInContainer)` // and `layoutManager.lineFragmentRect(forGlyphAt: lastGlyphOfColumn, effectiveRange: nil) Apple Documentation notes that both these calls force glyph generation and layout. As I'm in early development, I have not set non-contiguous layout. So these should be causing full layout, assuring accurate return values. Or so I'd hoped. This does work fine in many cases. I edit. Pagination works. But then I'll encounter UI-breaking inconsistent returns from these two calls. By inconsistent, I mean that the second call returns a line fragment rect that is in the container coordinates of A DIFFERENT container than the container returned by the first call. To be specific, the line fragment rect seems to be in the coordinates of the container that comes next in layoutManager.textContainers. Example Code: if !layoutManager.textContainers.indices.contains(i) { containerToUse = createTextContainer(with: availableSize) layoutManager.addTextContainer(containerToUse) } else { // We have a container already but it may be // the wrong size. containerToUse = layoutManager.textContainers[i] if containerToUse.size.width != availableSize.width { // Mandatory that we resize if we don't have // a matching width. Height resizing is not // mandatory and requires a layout check below. containerToUse.size = availableSize } } let glyphRange = layoutManager.glyphRange(forCharacterRange: remainingColumnRange, actualCharacterRange: nil) let lastGlyphOfColumn = NSMaxRange(glyphRange) - 1 var containerForLastGlyphOfColumn = layoutManager.textContainer(forGlyphAt: lastGlyphOfColumn, effectiveRange: &actualGlyphRangeInContainer) if containerForLastGlyphOfColumn != containerToUse && containerToUse.size.height < availableSize.height { // If we are here, we overflowed the container, // BUT the container we overflowed didn't use // the maximum remaining page space (this // means it was a pre-existing container that // needs to be sized up and checked once more). // NOTE RE: THE BUG: // at this point, prints show... // containerToUse.size.height // =628 // availableSize.height // =648 containerToUse.size = availableSize containerForLastGlyphOfColumn = layoutManager.textContainer(forGlyphAt: lastGlyphOfColumn, effectiveRange: &actualGlyphRangeInContainer) } // We now check again, knowing that the container we // are testing flow into is the max size it can be. if containerForLastGlyphOfColumn != containerToUse { // If we are here, we have overflowed the // container, so containerToUse size SHOULD be // final/accurate, since it is fully used. actualCharRangeInContainer = layoutManager.characterRange(forGlyphRange: actualGlyphRangeInContainer, actualGlyphRange: nil) // Start of overflow range is the first character // in the container that was overflowed into. let overflowLoc = actualCharRangeInContainer.location remainingColumnRange = NSRange(location: overflowLoc, length: remainingColumnRange.length - overflowLoc) // Update page count as we have broken to a new page currentPage += 1 } else { // If we are here, we have NOT overflowed // from the container. BUT... // THE BUG: // ***** HERE IS THE BUG! ***** lineFragmentRectForLastChar = layoutManager.lineFragmentRect(forGlyphAt: lastGlyphOfColumn, effectiveRange: nil) let usedHeight = lineFragmentRectForLastChar.maxY // BUG: ^The lines of code above return a // fragment rect that is in the coordinates // of the WRONG text container. Prints show: // usedHeight // =14 // usedHeight shouldn't be just 14 if this is // the SAME container that, when it was 628 // high, resulted in text overflowing. // Therefore, the line fragment here seems // to be in the coordinates of the ENSUING // container that we overflowed INTO, but // that shouldn't be possible, since we're in // a closure for which we know: // // containerForLastGlyphOfColumn == containerToUse // // If the last glyph container is the container // we just had to size UP, why does the final // glyph line fragment rect have a maxY of 14!? // Including ensuing code below only for context. if usedHeight < containerToUse.size.height { // Adjust container size down to usedRect containerToUse.size = CGSize(width: containerToUse.size.width, height: usedHeight) } else if usedHeight == availableSize.height { // We didn't force break to a new page BUT // we've used exactly the height of our page // to layout this column range, so need to // break to a new page for any ensuing text // columns. currentPage += 1 } else if usedHeight > containerToUse.size.height { // We should have caught this earlier. Text // has overflowed, but this should've been // caught when we checked // containerForLastGlyphOfColumn != // containerToUse. // // Note: this error has never thrown. throw PaginationError.unknownError("Oops.") } } Per my comments in the code block above, I don't understand why the very same text container that just overflowed and so had to be sized up from 628 to 648 in order to try to fit a glyph would now report that same glyph as both being IN that same container and having a line fragment rect with a maxY of just 14. A glyph couldn't fit in a container when it was 628 high, but if I size it up to 648, it only needs 14? There's something very weird going on here. Working with NSLayoutManager is a bit of a nightmare given the unclear documentation. Any help or insight here would be massively, massively appreciated.
Replies
2
Boosts
0
Views
554
Activity
Feb ’25
Simulating key press event to type text in UITextField
in iOS, user can set focus on UItextField and tapping a key in the virtual keyboard updates the text in the textfield. This user action causes the relevant delegates of UITextFieldDelegate to get invoked, i.e the handlers associated with action of user entering some text in the textfield. I m trying to simulate this user action where I am trying to do this programatically. I want to simulate it in a way such that all the handlers/listeners which otherwise would have been invoked as a result of user typing in the textfield should also get invoked now when i am trying to do it programatically. I have a specific usecase of this in my application. Below is how I m performing this simulation. I m manually updating the text field associated(UITextField.text) and updating its value. And then I m invoking the delegate manually as textField.delegate?.textField?(textField, shouldChangeCharactersIn: nsRange, replacementString: replacementString) I wanted to know If this is the right way to do this. Is there something better available that can be used, such that simulation has the same affect as the user performing the update?
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
4
Boosts
0
Views
405
Activity
Feb ’25
Swift Charts: How to prevent scroll position jump when loading more data dynamically
I'm implementing infinite scrolling with Swift Charts where additional historical data loads when scrolling near the beginning of the dataset. However, when new data is loaded, the chart's scroll position jumps unexpectedly. Current behavior: Initially loads 10 data points, displaying the latest 5 When scrolling backwards with only 3 points remaining off-screen, triggers loading of 10 more historical points After loading, the scroll position jumps to the 3rd position of the new dataset instead of maintaining the current view Expected behavior: Scroll position should remain stable when new data is loaded User's current view should not change during data loading Here's my implementation logic using some mock data: import SwiftUI import Charts struct DataPoint: Identifiable { let id = UUID() let date: Date let value: Double } class ChartViewModel: ObservableObject { @Published var dataPoints: [DataPoint] = [] private var isLoading = false init() { loadMoreData() } func loadMoreData() { guard !isLoading else { return } isLoading = true let newData = self.generateDataPoints( endDate: self.dataPoints.first?.date ?? Date(), count: 10 ) self.dataPoints.insert(contentsOf: newData, at: 0) self.isLoading = false print("\(dataPoints.count) data points.") } private func generateDataPoints(endDate: Date, count: Int) -> [DataPoint] { var points: [DataPoint] = [] let calendar = Calendar.current for i in 0..<count { let date = calendar.date( byAdding: .day, value: -i, to: endDate ) ?? endDate let value = Double.random(in: 0...100) points.append(DataPoint(date: date, value: value)) } return points.sorted { $0.date < $1.date } } } struct ScrollableChart: View { @StateObject private var viewModel = ChartViewModel() @State private var scrollPosition: Date @State private var scrollDebounceTask: Task<Void, Never>? init() { self.scrollPosition = .now.addingTimeInterval(-4*24*3600) } var body: some View { Chart(viewModel.dataPoints) { point in BarMark( x: .value("Time", point.date, unit: .day), y: .value("Value", point.value) ) } .chartScrollableAxes(.horizontal) .chartXVisibleDomain(length: 5 * 24 * 3600) .chartScrollPosition(x: $scrollPosition) .chartXScale(domain: .automatic(includesZero: false)) .frame(height: 300) .onChange(of: scrollPosition) { oldPosition, newPosition in scrollDebounceTask?.cancel() scrollDebounceTask = Task { try? await Task.sleep(for: .milliseconds(300)) if !Task.isCancelled { checkAndLoadMoreData(currentPosition: newPosition) } } } } private func checkAndLoadMoreData(currentPosition: Date?) { guard let currentPosition, let earliestDataPoint = viewModel.dataPoints.first?.date else { return } let timeInterval = currentPosition.timeIntervalSince(earliestDataPoint) if timeInterval <= 3 * 24 * 3600 { viewModel.loadMoreData() } } } I attempted to compensate for this jump by adding: scrollPosition = scrollPosition.addingTimeInterval(10 * 24 * 3600) after viewModel.loadMoreData(). However, this caused the chart to jump in the opposite direction by 10 days, rather than maintaining the current position. What's the problem with my code and how to fix it?
Replies
6
Boosts
0
Views
607
Activity
Feb ’25
VisionOS custom hover effect and click sound
I have created a custom hover effect per this WWDC video and many other examples on the Net: https://developer.apple.com/videos/play/wwdc2024/10152/ I can get the button to expand when looked at within a VisionOS device and it will invoke a tap event when tapped but there is no click sound like a normal SwiftUI button does in VisionOS! I can't for the life of me figure out why. Any help would be appreciated!
Replies
2
Boosts
0
Views
314
Activity
Feb ’25
Scroll to Top gesture breaks when setting List or ScrollView background
When a ScrollView or List is nested in a TabView, you can press on the tab button and the scroll view will scroll to top. import SwiftUI struct SwiftUIView: View { let items = (1...100).map { "Item \($0)" } var body: some View { TabView { Tab("home", systemImage: "house") { ScrollView { ForEach(items, id: \.self) { item in Text(item) .frame(maxWidth: .infinity, alignment: .center) } } } } } } #Preview { SwiftUIView() } But if we add a background to the ScrollView, the scroll to top gesture breaks. import SwiftUI struct SwiftUIView: View { let items = (1...100).map { "Item \($0)" } var body: some View { TabView { Tab("home", systemImage: "house") { ScrollView { ForEach(items, id: \.self) { item in Text(item) .frame(maxWidth: .infinity, alignment: .center) } } // Set background on ScrollView. .background(Color.red) } } } } #Preview { SwiftUIView() } I made a similar post on StackOverflow, but haven't been able to find a proper solution. This feels like a bug of some sort in SwiftUI.
Replies
1
Boosts
2
Views
285
Activity
Feb ’25
Control Widget SF image cannot stably display
I'm working on the control widget which should display the SF image on the UI, but I have found that it cannot be displayed stably. I have three ExampleControlWidget which is about the type egA egB and egC, it should all be showed but now they only show the text and placeholder. I'm aware of the images should be SF image and I can see them to show perfectly sometimes, but in other time it is just failed. This's really confused me, can anyone help me out? public enum ControlWidgetType: Sendable { case egA case egB case egC public var imageName: String { switch self { case .egA: return "egA" case .egB: return "egB" case .egC: return "egC" } } } struct ExampleControlWidget: ControlWidget { var body: some ControlWidgetConfiguration { AppIntentControlConfiguration( kind: kind, provider: Provider() ) { example in ControlWidgetToggle( example.name, isOn: example.state.isOn, action: ExampleControlWidgetIntent(id: example.id), valueLabel: { isOn in ExampleControlWidgetView( statusText: isOn ? Localization.on.text : Localization.off.text, bundle: bundle, widgetType: .egA //or .egB .egC ) .symbolEffect(.pulse) } ) .disabled(example.state.isDisabled) } .promptsForUserConfiguration() } } public struct ExampleControlWidgetView: View { private let statusText: String private let bundle: Bundle private var widgetType: ControlWidgetType = .egA public init(statusText: String, bundle: Bundle, widgetType: ControlWidgetType) { self.statusText = statusText self.bundle = bundle self.widgetType = widgetType } public var body: some View { Label( statusText, image: .init( name: widgetType.imageName, // the SF Symbol image id bundled in the Widget extension bundle: bundle ) ) } } This is the normal display: These are the display that do not show properly: The results has no rules at all, I have tried to completely uninstall the APP and reinstall but the result is same.
Replies
3
Boosts
0
Views
388
Activity
Feb ’25
How to keep sidebar always open on macOS 12.0 in SwiftUI?
Consider this code: import SwiftUI struct ContentView: View { var body: some View { NavigationView { EmptyView() } } } Which looks like this: How can I prevent the sidebar from being resized by a mouse and from being hidden? P.S. Can consider using AppKit if it can help.
Replies
2
Boosts
0
Views
522
Activity
Mar ’25
UITextView crash on iOS 18.4 beta
UITextView crash when setting attributed text that contains substring ffi and attributedText contains NSFontAttributeName, NSForegroundColorAttributeName Reproducible case: UITextView *textView = [[UITextView alloc] init]; textView.attributedText = [[NSAttributedString alloc] initWithString:@"ffi" attributes:@{ NSParagraphStyleAttributeName: [self createParagraphOfLineHeight:20], NSFontAttributeName: [UIFont systemFontOfSize:fontSize weight:UIFontWeightRegular], NSForegroundColorAttributeName: UIColor.black }];
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
9
Boosts
2
Views
2.2k
Activity
Mar ’25
SwiftUI Table performance issue
I found the Table with Toggle will have performance issue when the data is large. I can reproduce it in Apple demo: https://developer.apple.com/documentation/swiftui/building_a_great_mac_app_with_swiftui Replace with a large mock data, for example database.json Try to scroll the table, it's not smooth. I found if I delete the Toggle, the performance be good. TableColumn("Favorite", value: \.favorite, comparator: BoolComparator()) { plant in Toggle("Favorite", isOn: $garden[plant.id].favorite) .labelsHidden() } Is this bug in SwiftUI? Any workaround? My Mac is Intel, not sure it can repro on Apple Silicon
Replies
2
Boosts
0
Views
507
Activity
Mar ’25
AppIntent perform method not called.
We have a widget bundle with multiple widgets. I'm adding a widget that is interactive (iOS 17 and higher). Our widget code is in a static library that gets linked into the widget extension target in our main app Xcode project. I have SwiftUI buttons constructed with the intent constructor in our UI See https://developer.apple.com/documentation/swiftui/button/init(intent:label:) When I press the button the timeline refreshes (conforming to TimelineProvider) but the perform method doesn't seem to be called. I've seen multiple pieces of advice and none of them seem to work. I've tried on a physical device and a simulator. I've tried adding an AppIntentsPackage. I've tried including the AppIntent code in the app and the widget. I've tried setting the openAppWhenRun to true and false and not setting it at all. I've tried simplifying the intent to just printing out a line to the console and returning a result. At this point I have no idea how to debug this and I don't know what else to try. I appreciate any helpful advice at this point.
Replies
4
Boosts
0
Views
364
Activity
Mar ’25
SwiftUI Preview Runtime linking failure
I'm using GoogleMaps in my project. Legacy preview works well but new preview (Xcode 16.3.1 beta) produces error. It doesn't seem to find Googlemaps.a. == PREVIEW UPDATE ERROR: FailedToLaunchAppError: Failed to launch *** ================================== | [Remote] JITError | | ================================== | | | [Remote] CouldNotLoadInputStaticArchiveFile: Could not load static archive during preview: /Users/xxx/Library/Developer/Xcode/DerivedData/BOA-eiluspltxasszsfkpqrnnsxsjhth/Build/Products/Debug_BOA_Inhouse-iphonesimulator/GoogleMaps.a | | | | path: /Users/xxx/Library/Developer/Xcode/DerivedData/BOA-eiluspltxasszsfkpqrnnsxsjhth/Build/Products/Debug_BOA_Inhouse-iphonesimulator/GoogleMaps.a | | | | ================================== | | | | | [Remote] XOJITError | | | | | | XOJITError: arm64 slice of /Users/xxx/Library/Developer/Xcode/DerivedData/BOA-eiluspltxasszsfkpqrnnsxsjhth/Build/Products/Debug_BOA_Inhouse-iphonesimulator/GoogleMaps.a does not contain an archive
Replies
12
Boosts
0
Views
1.6k
Activity
Mar ’25
[StoreKit] Runtime warning with manageSubscriptionsSheet and ObservableObject
The following runtime warning is emitted by Xcode when using the manageSubscriptionsSheet with an ObservableObject: \ContentViewModel.isPresented is isolated to the main actor. Accessing it via Binding from a different actor will cause undefined behaviors, and potential data races; This warning will become a runtime crash in a future version of SwiftUI. Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates. This minimal sample project reproduces the issue: class ContentViewModel: ObservableObject { @Published var isPresented = false func didTapButton() { self.isPresented = true } } struct ContentView: View { @ObservedObject var viewModel: ContentViewModel var body: some View { Button("Tap me") { self.viewModel.didTapButton() } .manageSubscriptionsSheet(isPresented: self.$viewModel.isPresented) } } Reproduced on: Xcode 16.2 Xcode 16.3 beta both with a simulator and a real device. This doesn't happen when using @Observable.
Replies
1
Boosts
1
Views
273
Activity
Mar ’25
iOS 18.4 Beta: On iPhones which support Dynamic Island, the AppDelegate method applicationDidBecomeActive() takes longer to be called.
When testing with iOS 18.4 Beta on iPhones which support Dynamic Island, after doing a Face ID authentication, the amount of time it takes before the AppDelegate method applicationDidBecomeActive() is called takes longer than iPhones that do not support Dynamic Island. The time it takes is about double, 1.2 seconds vs 2.5 seconds on average. This does not occur with versions before 18.4 Beta. Anyone else seeing this?
Topic: UI Frameworks SubTopic: UIKit
Replies
2
Boosts
3
Views
381
Activity
Mar ’25
NSTextLineFragment crash - how to debug
We have crash reports as shown below that we haven't yet been able to repro and could use some help deubgging. My guess is that the app is giving a label or text view an attributed string with an invalid attribute range, but attributed strings are used in many places throughout the app, and I don't know an efficient way to track this down. I'm posting the stack trace here in hopes that someone more familiar with the internals of the system frameworks mentioned will be able to provide a clue to help narrow where I should look. Fatal Exception: NSRangeException NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds 0 CoreFoundation 0x2d5fc __exceptionPreprocess 1 libobjc.A.dylib 0x31244 objc_exception_throw 2 Foundation 0x47130 blockForLocation 3 UIFoundation 0x2589c -[NSTextLineFragment _defaultRenderingAttributesAtCharacterIndex:effectiveRange:] 4 UIFoundation 0x25778 __53-[NSTextLineFragment initWithAttributedString:range:]_block_invoke 5 CoreText 0x58964 TLine::DrawGlyphsWithAttributeOverrides(TLineDrawContext const&, __CFDictionary const* (long, CFRange*) block_pointer, TDecoratorObserver*) const 6 CoreText 0x58400 CTLineDrawWithAttributeOverrides 7 UIFoundation 0x25320 _NSCoreTypesetterRenderLine 8 UIFoundation 0x24b10 -[NSTextLineFragment drawAtPoint:graphicsContext:] 9 UIFoundation 0x3e634 -[NSTextLineFragment drawAtPoint:inContext:] 10 UIFoundation 0x3e450 -[NSTextLayoutFragment drawAtPoint:inContext:] 11 UIKitCore 0x3e3098 __38-[_UITextLayoutFragmentView drawRect:]_block_invoke 12 UIKitCore 0x3e31cc _UITextCanvasDrawWithFadedEdgesInContext 13 UIKitCore 0x3e3040 -[_UITextLayoutFragmentView drawRect:] 14 UIKitCore 0xd7a98 -[UIView(CALayerDelegate) drawLayer:inContext:] 15 QuartzCore 0x109340 CABackingStoreUpdate_ 16 QuartzCore 0x109224 invocation function for block in CA::Layer::display_() 17 QuartzCore 0x917f0 -[CALayer _display] 18 QuartzCore 0x90130 CA::Layer::layout_and_display_if_needed(CA::Transaction*) 19 QuartzCore 0xe50c4 CA::Context::commit_transaction(CA::Transaction*, double, double*) 20 QuartzCore 0x5bd8c CA::Transaction::commit() 21 UIKitCore 0x9f3f0 _UIApplicationFlushCATransaction 22 UIKitCore 0x9c89c __setupUpdateSequence_block_invoke_2 23 UIKitCore 0x9c710 _UIUpdateSequenceRun 24 UIKitCore 0x9f040 schedulerStepScheduledMainSection 25 UIKitCore 0x9cc5c runloopSourceCallback 26 CoreFoundation 0x73f4c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ 27 CoreFoundation 0x73ee0 __CFRunLoopDoSource0 28 CoreFoundation 0x76b40 __CFRunLoopDoSources0 29 CoreFoundation 0x75d3c __CFRunLoopRun 30 CoreFoundation 0xc8284 CFRunLoopRunSpecific 31 GraphicsServices 0x14c0 GSEventRunModal 32 UIKitCore 0x3ee674 -[UIApplication _run] 33 UIKitCore 0x14e88 UIApplicationMain also filed as FB16905066
Replies
6
Boosts
1
Views
535
Activity
Mar ’25
Collection view with self-sizing cells with SwiftUI content
I am trying to make a collection view with self-sizing cells that adapt to SwiftUI content. My test platform is macOS, but it should work on iOS all the same. I chose macOS because on macOS, you can resize the window and cause more interesting scenarios with that. My layout intent is fairly simple: a one-column collection view with cells with SwiftUI content, where the collection view cells should adapt to the height of their SwiftUI content. I got it working almost correctly. The one scenario that I don’t have working is window resizing. When the window resizes, the layout and cells should adapt to the content and change their heights. I feel that I am missing something fairly basic. How do I change this project so that the layout works correctly when I change the macOS window width? Example project and video of the behavior: https://gist.github.com/jaanus/66e3d863941ba645c88220b8a22970e1
Topic: UI Frameworks SubTopic: AppKit
Replies
1
Boosts
0
Views
384
Activity
Mar ’25
Crash when assigning NSImage to `@objc dynamic var` property
Xcode downloaded a crash report for my app which I don't quite understand. It seems the following line caused the crash: myEntity.image = newImage where myEntity is of type MyEntity: class MyEntity: NSObject, Identifiable { @objc dynamic var image: NSImage! ... } The code is called on the main thread. According to the crash report, thread 0 makes that assignment, and at the same time thread 16 is calling [NSImageView asynchronousPreparation:prepareResultUsingParameters:]. What could cause such a crash? Could I be doing something wrong or is this a bug in macOS? crash.crash
Replies
11
Boosts
0
Views
259
Activity
Mar ’25