Performance

RSS for tag

Improve your app's performance.

Posts under Performance tag

36 Posts

Post

Replies

Boosts

Views

Activity

Inconsistent subviews redrawing in LazyVStack
Hello Apple forum ! I spotted a weird behaviour with LazyVStack in a ScrollView. I understand that it loads its views only once upon appearance unlinke VStack that loads everything in one shot. What I noticed also, it seems to reload its views sometimes when scrolling back up to earlier loaded views. The thing is, it isn't always the case. struct LazyVStackTest: View { var body: some View { ScrollView { LazyVStack { ForEach(0..<1000, id: \.self) { _ in // if true { MyText() // } } } } } struct MyText: View { var body: some View { let _ = Self._printChanges() HStack { Text("hello") } } } } If we consider the code above on XCode 26 beta 7 on an iOS 26 or iOS 18.2 simulator. Scroll to the bottom : you'll see one "LazyVStackTest.MyText: @self changed" for each row. Then scroll back up to the top, we'll see again the same message printed multiple times. --> So I gather from this that LazyVStack not only loads lazily but also removes old rows from memory & recreates them upon reappearance. What I don't get however is that if you uncomment the "if true" statement, you won't see the reloading happening. And I have absolutely no clue as to why 😅 If someone could help shed some light on this weird behaviour, it would be greatly appreciated ^^ PS : the issue is also present with XCode 16.2 but at a deeper lever (ex: if we embed another custom View "MyText2" inside "MyText", the reloading is in "MyText2" & not "MyText")
0
0
145
3w
Why does CADisplayLink of an external UIScreen drift in time?
I am using Apple's original Lightning Digital AV-adapter (Lightning-to-HDMI dongle) to connect my iPhone to an external display via a HDMI cable. I need to synchronize rendering with the external display's refresh rate, so I create a new CADisplayLink tied to the external display's UIScreen: UIScreen.screens[externalDisplayIdx].displayLink(withTarget:, selector:). The callback is being called regularly, but with increasing delay relative to the CADisplayLink.timestamp, so the next time the callback is called, I have less and less time to draw the next frame (see the snippet below). Assuming 60 FPS, the value of secondsTillDeadline starts at an arbitrary value in the range of approx -0.0001 to 0.0166667, and then it slowly decreases towards zero (and for a brief period it goes into small negative numbers). Once it reaches zero, it flips back to 0.0166667 and continues to decrease again. This cycle repeats indefinitely. Changing the external display's resolution (UIScreen's mode) or the CADisplayLink's preferredFrameRateRange to a lower FPS does not seem to have any effect on the temporal drifting (even the rate of change seem to be the same). When I create a new CADisplayLink for the iPhone's main screen, the value of secondsTillDeadline is stable, it does not drift and it is very close to 0.0166667, as expected. Is this drift caused by the external monitor or by Apple's Lightning-to-HDMI dongle ...or is the problem somewhere else? Can the drifting be stopped? func onDisplayLinkUpdate(displayLink: CADisplayLink) { // Gradually decreases from 0.01667 to -0.0001, then flips back to 0.01667 and continues to decrease let secondsTillDeadline = displayLink.targetTimestamp - CACurrentMediaTime() }
3
0
198
Aug ’25
JAX Metal: Random Number Generation Performance Issue on M1 Max
JAX Metal shows 55x slower random number generation compared to NVIDIA CUDA on equivalent workloads. This makes Monte Carlo simulations and scientific computing impractical on Apple Silicon. Performance Comparison NVIDIA GPU: 0.475s for 12.6M random elements M1 Max Metal: 26.3s for same workload Performance gap: 55x slower Environment Apple M1 Max, 64GB RAM, macOS Sequoia Version 15.6.1 JAX 0.4.34, jax-metal latest Backend: Metal Reproduction Code import time import jax import jax.numpy as jnp from jax import random key = random.PRNGKey(42) start_time = time.time() random_array = random.normal(key, (50000, 252)) duration = time.time() - start_time print(f"Duration: {duration:.3f}s")
0
0
274
Aug ’25
Request for Device Temperature Monitoring and Thermal Attribution Analysis APIs
Background: During daily usage of iOS devices, devices experience noticeable thermal issues. This heating not only affects user experience, but may also lead to device performance throttling, shortened battery life, and other problems. We need better understanding and monitoring of device thermal states to optimize application performance and user experience. Issues Encountered: Insufficient thermal monitoring capabilities: Unable to obtain real-time accurate temperature data from devices Difficult power consumption analysis: Hard to determine which specific modules or threads cause high power consumption and heating Requested Solutions: Temperature Monitoring API: Provide accessible device temperature reading interfaces Thermal Attribution Analysis Capability: During heating events, we expect to receive more detailed power consumption monitoring data, such as CPU, GPU, network, location services, display, high power consumption thread stacks and other information to help developers identify high energy consumption operations
2
0
51
Aug ’25
How to get UITextView to fit inside container, AND auto wrap
I am currently having an issue in where whenever I place a UITextView with text that's long, it simply pushes past the width of the container it is in, and when I do try and set a width, it does auto wrap and ignores that. I do not come from UIKit and come from SwiftUI, through a mix of ChatGPT and Stack overflow, I have come up with this solution, however, are there any better/simpler ones, I dont want to have to use expensive GeoReaders just to get a width. struct AutoDetectedPhoneNumberView: UIViewRepresentable { let text: String var width: CGFloat func makeUIView(context: Context) -> UITextView { let textView = UITextView() textView.dataDetectorTypes = [.phoneNumber] textView.isEditable = false textView.isScrollEnabled = false textView.backgroundColor = .clear textView.font = UIFont.systemFont(ofSize: 16) textView.textContainer.lineBreakMode = .byWordWrapping textView.translatesAutoresizingMaskIntoConstraints = false print(width) NSLayoutConstraint.activate([ textView.widthAnchor.constraint(equalToConstant: width) ]) return textView } func updateUIView(_ uiView: UITextView, context: Context) { uiView.text = text } } GeometryReader { geo in AutoDetectedPhoneNumberView(text: phone, width: geo.size.width) }
0
0
86
Jul ’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
302
Jul ’25
How to Enable Game Mode
What is Game Mode? Game Mode optimizes your gaming experience by giving your game the highest priority access to your CPU and GPU, lowering usage for background tasks. And it doubles the Bluetooth sampling rate, which reduces input latency and audio latency for wireless accessories like game controllers and AirPods. See Use Game Mode on Mac See Port advanced games to Apple platforms How can I enable Game Mode in my game? Add the Supports Game Mode property (GCSupportsGameMode) to your game’s Info.plist and set to true Correctly identify your game’s Application Category with LSApplicationCategoryType (also Info.plist) Note: Enabling Game Mode makes your game eligible but is not a guarantee; the OS decides if it is ok to enable Game Mode at runtime An app that enables Game Mode but isn’t a game will be rejected by App Review. How can I disable Game Mode? Set GCSupportsGameMode to false. Note: On Mac Game Mode is automatically disabled if the game isn’t running full screen.
1
0
298
Jul ’25
Can Game Mode be activated when a child (Java) process's window is fullscreened?
Imagine a native macOS app that acts as a "launcher" for a Java game.** For example, the "launcher" app might use the Swift Process API or a similar method to run the java command line tool (lets assume the user has installed Java themselves) to run the game. I have seen How to Enable Game Mode. If the native launcher app's Info.plist has the following keys set: LSApplicationCategoryType set to public.app-category.games LSSupportsGameMode set to true (for macOS 26+) GCSupportsGameMode set to true The launcher itself can cause Game Mode to activate if the launcher is fullscreened. However, if the launcher opens a Java process that opens a window, then the Java window is fullscreened, Game Mode doesn't seem to activate. In this case activating Game Mode for the launcher itself is unnecessary, but you'd expect Game Mode to activate when the actual game in the Java window is fullscreened. Is there a way to get Game Mode to activate in the latter case? ** The concrete case I'm thinking of is a third-party Minecraft Java Edition launcher, but the issue can also be demonstrated in a sample project (FB13786152). It seems like the official Minecraft launcher is able to do this, though it's not clear how. (Is its bundle identifier hardcoded in the OS to allow for this? Changing a sample app's bundle identifier to be the same as the official Minecraft launcher gets the behavior I want, but obviously this is not a practical solution.)
2
0
149
Jun ’25
Can child processes inherit Info.plist properties of a parent app (such as LSSupportsGameMode)?
My high-level goal is to add support for Game Mode in a Java game, which launches via a macOS "launcher" app that runs the actual java game as a separate process (e.g. using the java command line tool). I asked this over in the Graphics & Games section and was told this, which is why I'm reposting this here. I'm uncertain how to speak to CLI tools and Java games launched from a macOS app. These sound like security and sandboxing questions which we recommend you ask about in those sections of the forums. The system seems to decide whether to enable Game Mode based on values in the Info.plist (e.g. for LSApplicationCategoryType and GCSupportsGameMode). However, the child process can't seem to see these values. Is there a way to change that? (The rest of this post is copied from my other forums post to provide additional context.) Imagine a native macOS app that acts as a "launcher" for a Java game.** For example, the "launcher" app might use the Swift Process API or a similar method to run the java command line tool (lets assume the user has installed Java themselves) to run the game. I have seen How to Enable Game Mode. If the native launcher app's Info.plist has the following keys set: LSApplicationCategoryType set to public.app-category.games LSSupportsGameMode set to true (for macOS 26+) GCSupportsGameMode set to true The launcher itself can cause Game Mode to activate if the launcher is fullscreened. However, if the launcher opens a Java process that opens a window, then the Java window is fullscreened, Game Mode doesn't seem to activate. In this case activating Game Mode for the launcher itself is unnecessary, but you'd expect Game Mode to activate when the actual game in the Java window is fullscreened. Is there a way to get Game Mode to activate in the latter case? ** The concrete case I'm thinking of is a third-party Minecraft Java Edition launcher, but the issue can also be demonstrated in a sample project (FB13786152). It seems like the official Minecraft launcher is able to do this, though it's not clear how. (Is its bundle identifier hardcoded in the OS to allow for this? Changing a sample app's bundle identifier to be the same as the official Minecraft launcher gets the behavior I want, but obviously this is not a practical solution.)
3
0
192
Jun ’25
Swift Charts - weak scrolling performance
Hello there! I wanted to give a native scrolling mechanism for the Swift Charts Graph a try and experiment a bit if the scenario that we try to achieve might be possible, but it seems that the Swift Charts scrolling performance is very poor. The graph was created as follows: X-axis is created based on a date range, Y-axis is created based on an integer values between moreless 0-320 value. the graph is scrollable horizontally only (x-axis), The time range (x-axis) for the scrolling content was set to one year from now date (so the user can scroll one year into the past as a minimum visible date (.chartXScale). The X-axis shows 3 hours of data per screen width (.chartXVisibleDomain). The data points for the graph are generated once when screen is about to appear so that the Charts engine can use it (no lazy loading implemented yet). The line data points (LineMark views) consist of 2880 data points distributed every 5 minutes which simulates - two days of continuous data stream that we want to present. The rest of the graph displays no data at all. The performance result: The graph on the initial loading phase is frozen for about 10-15 seconds until the data appears on the graph. Scrolling is very laggy - the CPU usage is 100% and is unacceptable for the end users. If we show no data at all on the graph (so no LineMark views are created at all) - the result is similar - the empty graph scrolling is also very laggy. Below I am sharing a test code: @main struct ChartsTestApp: App { var body: some Scene { WindowGroup { ContentView() Spacer() } } } struct LineDataPoint: Identifiable, Equatable { var id: Int let date: Date let value: Int } actor TestData { func generate(startDate: Date) async -> [LineDataPoint] { var values: [LineDataPoint] = [] for i in 0..<(1440 * 2) { values.append( LineDataPoint( id: i, date: startDate.addingTimeInterval( TimeInterval(60 * 5 * i) // Every 5 minutes ), value: Int.random(in: 1...100) ) ) } return values } } struct ContentView: View { var startDate: Date { return endDate.addingTimeInterval(-3600*24*30*12) // one year into the past from now } let endDate = Date() @State var dataPoints: [LineDataPoint] = [] var body: some View { Chart { ForEach(dataPoints) { item in LineMark( x: .value("Date", item.date), y: .value("Value", item.value), series: .value("Series", "Test") ) } } .frame(height: 200) .chartScrollableAxes(.horizontal) .chartYAxis(.hidden) .chartXScale(domain: startDate...endDate) // one year possibility to scroll back .chartXVisibleDomain(length: 3600 * 3) // 3 hours visible on screen .onAppear { Task { dataPoints = await TestData().generate(startDate: startDate) } } } } I would be grateful for any insights or suggestions on how to improve it or if it's planned to be improved in the future. Currently, I use UIKit CollectionView where we split the graph into smaller chunks of the graph and we present the SwiftUI Chart content in the cells, so we use the scrolling offered there. I wonder if it's possible to use native SwiftUI for such a scenario so that later on we could also implement some kind of lazy loading of the data as the user scrolls into the past.
3
2
962
Jun ’25
Severe hangs with LazyHStack inside ScrollView
Hi, I got a problem with severe hangs when I use code like this on tvOS 18.2 If I try to use HStack instead of LazyHStack inside the scrollview then the problem does not occur any more but then the scroll performance is compromised and the vertical scroll is no longer that smooth. Does someone has any experience with this? Is this SwiftUI problem or am I missing something? ScrollView { LazyVStack { ForEach(0...100, id: \.self) { _ in ScrollView { LazyHStack { ForEach(0...20, id: \.self) { _ in Color.red.frame(height: 300) } } } } } }
2
0
101
Apr ’25
XPC - performance/load testing
I have an XPC server running on macOS and want to perform comprehensive performance and load testing to evaluate its efficiency, responsiveness, and scalability. Specifically, I need to measure factors such as request latency, throughput, and how well it handles concurrent connections under different load conditions. What are the best tools, frameworks, or methodologies for testing an XPC service? Additionally, are there any best practices for simulating real-world usage scenarios and identifying potential bottlenecks?
1
1
88
Apr ’25
Slow app launch time
Hello, We are experiencing slow launch time indicators in our performance monitoring tools(Crashlytics/DataDog/Xcode), and trying to understand what is the best approach to reduce it. Currently, cold launch takes ~900ms on iPhone 16 Pro , but ~2s on iPhone 11. Profiling app launch detected that most of the time is spend on loading the libraries. Our app is massive, we use a total of ~40 3rd parties libraries + 10 internal libraries. We enabled the "mergeable libraries" XCode new feature however the app launch is as written above. We also postponed some of the work in didFinishLaunch, which help a bit... But maybe we are trying to achieve the impossible? Could it be that large apps just can't reach the golden 500ms goal? Currently we are trying to create an "umbrella" library for all the third parties in order to force them to become part of the mergeable libraries. We would like to know if, are we on the right track?
0
0
293
Mar ’25
How can I optimize SwiftUI CPU load on frequent updates
Dear Sirs, I'm writing an audio application that should show up to 128 horizontal peakmeters (width for each is about 150, height is 8) stacked inside a ScrollViewReader. For the actual value of the peakmeter I have a binding to a CGFloat value. The peakmeter works as expected and is refreshing correct. For testing I added a timer to my swift application that is firing every 0.05 secs, meaning I want to show 20 values per second. Inside the timer func I'm just creating random CGFloat values in range of 0...1 for the bound values. The peakmeters refresh and flicker as expected but I can see a CPU load of 40-50% in the activity monitor on my MacBook Air with Apple M2 even when compiled in release mode. I think this is quite high and I'd like to reduce this CPU load. Should this be possible? I.e. I thought about blocking the refresh until I've set all values? How could this be done and would it help? What else could I do? Thanks and best regards, JFreyberger
7
0
1k
Feb ’25
Performance Implications of XPC polling
On my MAC, I have a XPC server running as a daemon. It also checks the clients for codesigning requirements. I have multiple clients(2 or more). Each of these clients periodically(say 5 seconds) poll the XPC server to ask for a particular data. I want to understand how the performance of my MAC will be affected when multiple XPC clients keep polling a XPC server.
4
0
412
Feb ’25
xCode Organizer hang issues & logs
Our team is currently handling hang issues and logs received by the Organizer during our project. Regarding the xCode Organizer, we’d like to ask a few questions: The hang rate is presented as a bar chart for each app version. Is there any way to get detailed information for each versions? For example, what percentage of the hang rate is attributed to users on different iOS versions? We've encountered a situation where the hang logs have decreased, but the hang rate has increased. Could you explain why this might occur? I was wondering how the hang rate is sampled. For instance, does it record all users who experience a hang, or only those under specific conditions? The situation is that we can see only a handful of hang logs (around 13), but we have hundreds of thousands of DAUs. This ratio seems quite off. Could you explain what might cause us to receive such a small number of logs for each version?
2
0
481
Jan ’25
Poor ScrollView performance
Hello, I have a scroll view that when it appears I get a constant stream of warnings from the console: CGBitmapContextInfoCreate: CGColorSpace which uses extended range requires floating point or CIF10 bitmap context This happens whether or not I'm actively scrolling, so maybe it's not a scroll view issue at all? The reason I initially thought it was a scrollView issue was because when I scrolled the scrolling was no longer smooth, it was pretty choppy. Also, I only get these warnings when I run my code on a real device - I do not get these on any simulators. Could it be the mesh gradient causing an issue? I'm not sure what's causing the issue so I apologize in advance for what may be irrelevant code. struct ModernStoryPicker: View { @Environment(CategoryPickerViewModel.self) var categoryPickerViewModel @EnvironmentObject var navigationPath: GrowNavigationState @State private var hasPreselectedStory: Bool = false @State private var storyGenerationType: StoryGenerationType = .arabicCompanion var userInstructions: String { if categoryPickerViewModel.userInputCategory.isEmpty { "Select a category" } else if categoryPickerViewModel.userInputSubCategory.isEmpty { "Select a subcategory" } else { "Select a story" } } var body: some View { ZStack { MeshGradient(width: 3, height: 3, points: [ [0.0, 0.0], [0.5, 0.0], [1.0, 0.0], [0.0, 0.5], [0.9, 0.3], [1.0, 0.5], [0.0, 1.0], [0.5, 1.0], [1.0, 1.0] ], colors: [ .orange, .indigo, .orange, .blue, .blue, .cyan, .green, .indigo, .pink ]) .ignoresSafeArea() VStack { Picker("", selection: $storyGenerationType) { ForEach(StoryGenerationType.allCases) { type in Text(type.rawValue).tag(type) } }.pickerStyle(.segmented) Text(userInstructions) .textScale(.secondary) automatedOrUserStories() Spacer() }.padding() } .onAppear {...} } @ViewBuilder func automatedOrUserStories() -> some View { switch storyGenerationType { case .userGenerated: VStack { Spacer() Text("Coming soon!") } case .arabicCompanion: VStack { // TODO: Unnecessary passing of data, only the 2nd view really needs all these props CategoryPickerView( categories: categoryPickerViewModel.mainCategories(), isSubCategory: false, selectionColor: .blue ) CategoryPickerView( categories: categoryPickerViewModel.subCategories(), isSubCategory: true, selectionColor: .purple ) ScrollView(.horizontal) { HStack { if categoryPickerViewModel.booksForCategories.isEmpty { Text("More books coming soon!") } ForEach(categoryPickerViewModel.booksForCategories) { bookCover in Button(action: { // navigates to BookDetailView.swift navigationPath.path.append(bookCover) }) { ModernStoryCardView( loadedImage: categoryPickerViewModel.imageForBook(bookCover), bookCover: bookCover ) .scrollTransition(axis: .horizontal) { content, phase in content .scaleEffect(phase.isIdentity ? 1 : 0.5) .opacity(phase.isIdentity ? 1 : 0.8) } }.buttonStyle(.plain) } }.scrollTargetLayout() } .contentMargins(80, for: .scrollContent) .scrollTargetBehavior(.viewAligned) }.padding() } } } struct CategoryPickerView: View { @Environment(CategoryPickerViewModel.self) var viewModel let categories: [String] let isSubCategory: Bool let selectionColor: Color var body: some View { ScrollView(.horizontal) { HStack { ForEach(categories, id: \.self) { category in Button(action: { withAnimation { selectCategory(category) } }) { TextRoundedRectangleView(text: category, color: effectiveColor(for: category)) .tag(category) }.buttonStyle(.plain) } } }.scrollIndicators(.hidden) } private func selectCategory(_ string: String) { if !isSubCategory { viewModel.userInputCategory = string } else { viewModel.userInputSubCategory = string } } private func effectiveColor(for category: String) -> Color { let chosenCategory = isSubCategory ? viewModel.userInputSubCategory : viewModel.userInputCategory if category == chosenCategory { return selectionColor } return .white } }
4
0
630
Jan ’25
WKWebview termination due to memory. Adjustable threshold for termination?
Hi, Our company has an application uses the WKWebview to host a lot of content. The content is web based and hosts a lot of charts and metrics. Because of the high content, we've seen the memory of the WebContent hit above 1.25 GB. When that happens, it'll eventually terminate and we have our recovery code to reload the same page Seems like the limit is hidden / internal. Some Apple devs also noted something might be hard coded to be limited as well. Yes, we have our optimizations but we still need to keep our queries, use react, cache, etc... It's just a heavy web application. Request: Can you help us raise that limit? Are there some limitations in Webkit for such a need to terminate? As some devices have much higher RAM than before, we were hoping to be able to dynamically adjust the limit for the wkwebview before it resets. We contacted our internal contacts but they said to post here.
0
1
453
Jan ’25
Slow performance decoding large images with Core Image.
I'm building a camera app that does some post processing after the photo has been taken. With 12MP the processing is pretty good, but larger images 24MP is very slow. I created a very simple example to demonstrate the issue, which is loading an image and the rendering it to data. let context = CIContext() let imageUrl = Bundle.main.url(forResource: "12mp", withExtension: "jpg")! let data = try! Data(contentsOf: imageUrl) let ciImage = CIImage(data: data)! let start = CFAbsoluteTimeGetCurrent() let data = context.jpegRepresentation(of: ciImage, colorSpace: context.workingColorSpace!) print(data?.count) print("Resize Completed: " + String(CFAbsoluteTimeGetCurrent() - start)) Running this code on an iPhone 16 Pro with different images produces these benchmarks: 12MP => 0.03s 24MP => 1.22s 48MP => 2.98s I understand that processing time will increase with resolution but it doesn't seem linear. I have tried setting different CiContext options such as .useSoftwareRenderer: false but it has made no difference. From profiling the process it looks like the JPEG decoding is the bottle neck. This is for a 48MP Image: Is there any way this can be improved?
0
0
583
Dec ’24