Things to Test When Upgrading XCode
Encountering ghost crashes or logical issues that only appear in Build Configuration Release (production version) but not in Debug.
ℹ️ℹ️ℹ️ The following content is translated by OpenAI.
Click here to view the original Chinese version. | 點此查看本文中文版
[Things to Test] When Upgrading XCode
Encountering ghost crashes or logical issues that only appear in Build Configuration Release (production version) but not in Debug.
Photo by Tommaso Pecchioli
TL;DR
Before packaging and releasing your project with the new XCode, in addition to directly using Build & Run to check for layout issues or anomalies, please remember to also try:
- App Target
- Select
Build Settings
- Search for
Optimization Level
- Locate the
Optimization Level
section - Set the
Debug
environment to the same value asRelease
(e.g.Fastest, Smallest [-Os]
) - Build & Run to see if there are any anomalies
Not choosing to directly package and upload to TestFlight for testing is to facilitate finding the root cause of issues immediately using breakpoints when they arise.
If you encounter issues reported by users in Release (production version), but developers cannot reproduce them locally, you can also try changing this setting locally to see if it helps.
Possible Issues
- The program appears correct, but the results are abnormal
- Areas that should not crash the program do crash
All of the above are normal in the Debug environment with Optimization Level = None [-O0]
, and only occur with Optimization Level = Fastest, Smallest [-Os]
, which is the setting for Release.
Solution
If there are issues, they are mostly unrelated to the developer; they are caused by a bug in XCode’s optimization. If you must use this version of XCode for packaging, you can only adjust the program as a workaround and wait for a new version of XCode to see if it works correctly.
It is not recommended to change Release to None directly, as it may cause more issues.
Story Time
Here are some real scenarios from my work over the years where I encountered these pitfalls.
Story 1 — App Keeps Prompting Users to Rate the App
Our app previously had a feature that would “invite users to rate the app in the app store” when opened, with the rule that it would stop prompting after three times. However, we received many reports from users that they were prompted every time they opened the app, which became quite annoying.
From the code, we saw no issues, and it worked fine when we built and ran it on the simulator or real devices. We tried various edge cases but could not reproduce the problem; I even wrote a UI Test that repeatedly ran the path and cleared data to retry… after running it thousands of times, I still encountered no issues.
I remember being so frustrated at around 3 AM, feeling hopeless and unable to figure out the problem. I started aimlessly checking project settings and suddenly had a lightbulb moment to change all Build Settings
to the Release
values to see what would happen. That’s when I discovered the issue could be reproduced with Optimization Level = Fastest, Smallest [-Os]
, which helped me pinpoint the problem.
Pseudocode
1
2
3
4
5
6
7
8
9
10
11
12
var invitedTimes = 0 // Loaded from UserDefaults; will be saved back after update
func requestAppStoreReviewIfNeeded() {
defer {
invitedTimes += 1 // Works for now, but may have unintended side effects
}
guard invitedTimes < 3 else {
return
}
self.present(AppStoreReviewRequestAlert())
}
This piece of code was developed by someone else. Although it has a side effect, the logic seems fine, it compiles correctly, and previous versions executed without issues.
However, when I set Optimization Level = Fastest, Smallest [-Os]
and set a breakpoint to print the value, I found an anomaly: after invitedTimes += 1
, it exploded to -24760045646797946
, a huge negative number, causing users to be prompted for a rating every time.
I first changed the defer implementation here, and we never received similar reports from users again. Later, I tested subsequent XCode versions, and the same implementation with Optimization Level = Fastest, Smallest [-Os]
worked correctly.
Story 2 — A Page Crashes Immediately
During internal testing of the Release (TestFlight) version, we found that one page (WebView) would crash as soon as it was clicked, but engineers had no issues when building and running it on the simulator or real devices. Each time we guessed a potential issue, we would package a version with logs or attempted fixes for TestFlight testing, which was very painful and time-consuming. This reminded me of the fear I experienced last time, so I immediately asked a colleague to change the local settings to Optimization Level = Fastest, Smallest [-Os]
, and sure enough, we reproduced the crash locally.
The main issue was that in our custom WebView Obj-C code, a variable would become null when Optimization Level = Fastest, Smallest [-Os]
, for reasons unknown. We could only add additional checks for protection; it had worked fine in previous versions, and we would have to wait for a new XCode release to see if it worked correctly.
Conclusion
Actually, I have been caught in this trap more than twice, and I’ve forgotten some of them. In any case, here are some takeaways:
- When packaging for the first time with a new XCode version, it’s best to test this.
- If issues only occur in Release (production version), it’s likely this problem; you can directly change the settings locally to see if you can reproduce it.
If you have any questions or feedback, feel free to contact me.
This article was first published on Medium ➡️ Click Here
Automatically converted and synchronized using ZMediumToMarkdown and Medium-to-jekyll-starter.