概览
Xcode 15 在运行 SwiftUI 代码时突然报告如下警告:
Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored. Please fix this problem.
不仅如此,Xcode 调试控制台中还提示我们需要添加特定的环境变量以进一步与该错误“亲密接触”。可是我们应该如何添加环境变量呢?
在本篇博文中,您将学到如下内容:
- 概览
- 1. 事件始末
- 2. 按部就班:增加运行时环境变量
- 总结
相信学完本课后,头发茂密的小伙伴们会对 Xcode 中添加环境变量这一常规技能了然于胸、信手拈来!那还等什么呢?
Let‘s go!!!😉
1. 事件始末
在 Xcode 15.2 调试运行 SwiftUI(模拟器 iOS 版本 17.2)编写的应用时,出现了如下错误信息:
可以看到该“错误”的描述相当模棱两可,既无法意会,也不方便言传:“该应用程序或库向 CoreGraphics 接口传入了一个非法的数字值(NaN 或根本不是数字)”,这是个啥意思?
“肿”么会这样?难道源代码是外星人写的?
import SwiftUI
struct ContentView: View {
@State var name = ""
var body: some View {
VStack {
TextField("", text: $name)
.textFieldStyle(.roundedBorder)
}
.padding()
}
}
#Preview {
ContentView()
}
如上我们可以看到,源代码简单的不要不要的,并没有什么特别的地方:我们只是用一个其貌不扬的 TextField 来捕获用户的输入而已。
另外我们还注意到该错误在 Xcode 预览中并不会出现,只会在真机或模拟器上运行时才会“面目狰狞”。
2. 按部就班:增加运行时环境变量
如果小伙伴们仔细观察就会发现,该错误只是其一,实际上 Apple 在该错误之后立马就给出了进一步探查它的方法:
If you want to see the backtrace, please set CG_NUMERICS_SHOW_BACKTRACE environmental variable.
“如果想看到回溯(backtrace)信息,请设置 CG_NUMERICS_SHOW_BACKTRACE 环境变量”(这里的回溯应该是出现该问题时的栈回溯)
那么如何设置这一环境变量呢?
首先,在 Xcode 中编辑项目的 Scheme 配置:
接着选择 Run 配置中的 Arguments 选项卡,我们即可轻车熟路的所愿添加指定的环境变量了:
注意,它只要我们添加一个名为 CG_NUMERICS_SHOW_BACKTRACE 的环境变量,至于它的值是啥并没有什么毛线关系,实际上只要这个变量存在就可以了,如上图演示的那样我们没有为它设置任何值。
再次运行原先的代码,我们发现了“新大陆”:
Backtrace:
<CGPathMoveToPoint+84>
<+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadii:segments:smoothPillShapes:]+1120>
<+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadius:segments:]+180>
<+[UIBezierPath _roundedRectBezierPath:withRoundedCorners:cornerRadius:segments:legacyCorners:]+340>
<-[_UITextChoiceAccelerationBubble backgroundImageView]+156>
<-[_UITextChoiceAccelerationBubble anchorToTextIfNeeded]+500>
<-[_UITextChoiceAccelerationBubble updateTextAnchorForParentView:]+156>
<-[_UITextChoiceAccelerationBubble updateTextBoxHighlightForRect:inTextView:parentView:highlightColor:]+88>
<-[_UITextChoiceAccelerationAssistant updateActivePromptForCandidate:displayRects:highlightOnly:]+352>
<-[UIKeyboardImpl updateAutocorrectPrompt:correctionRects:]+492>
<-[UIKeyboardImpl updateAutocorrectPrompt:executionContext:]+608>
<__45-[UIKeyboardImpl touchAutocorrectPromptTimer]_block_invoke+112>
<__56-[UIKeyboardScheduledTask handleDeferredTimerFiredEvent]_block_invoke+184>
<-[UIKeyboardTaskEntry execute:]+200>
<-[UIKeyboardTaskQueue continueExecutionOnMainThread]+304>
<-[UIKeyboardTaskQueue addTask:]+92>
<-[UIKeyboardScheduledTask handleDeferredTimerFiredEvent]+216>
<__invoking___+144>
<-[NSInvocation invoke]+276>
<-[_UIActionWhenIdle invoke]+52>
<__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__+32>
<__CFRunLoopDoObservers+528>
<__CFRunLoopRun+968>
<CFRunLoopRunSpecific+572>
<GSEventRunModal+160>
<-[UIApplication _run]+868>
<UIApplicationMain+124>
<OUTLINED_FUNCTION_70+500>
<OUTLINED_FUNCTION_70+148>
<OUTLINED_FUNCTION_2+92>
<$s4test0A3AppV5$mainyyFZ+40>
<main+12>
102221544
1022ca0e0 487a800000000000
Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored. Please fix this problem.
Backtrace:
<CGPathAddLineToPoint+88>
<+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadii:segments:smoothPillShapes:]+1140>
<+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadius:segments:]+180>
<+[UIBezierPath _roundedRectBezierPath:withRoundedCorners:cornerRadius:segments:legacyCorners:]+340>
<-[_UITextChoiceAccelerationBubble backgroundImageView]+156>
<-[_UITextChoiceAccelerationBubble anchorToTextIfNeeded]+500>
<-[_UITextChoiceAccelerationBubble updateTextAnchorForParentView:]+156>
<-[_UITextChoiceAccelerationBubble updateTextBoxHighlightForRect:inTextView:parentView:highlightColor:]+88>
<-[_UITextChoiceAccelerationAssistant updateActivePromptForCandidate:displayRects:highlightOnly:]+352>
<-[UIKeyboardImpl updateAutocorrectPrompt:correctionRects:]+492>
<-[UIKeyboardImpl updateAutocorrectPrompt:executionContext:]+608>
<__45-[UIKeyboardImpl touchAutocorrectPromptTimer]_block_invoke+112>
<__56-[UIKeyboardScheduledTask handleDeferredTimerFiredEvent]_block_invoke+184>
<-[UIKeyboardTaskEntry execute:]+200>
<-[UIKeyboardTaskQueue continueExecutionOnMainThread]+304>
<-[UIKeyboardTaskQueue addTask:]+92>
<-[UIKeyboardScheduledTask handleDeferredTimerFiredEvent]+216>
<__invoking___+144>
<-[NSInvocation invoke]+276>
<-[_UIActionWhenIdle invoke]+52>
<__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__+32>
<__CFRunLoopDoObservers+528>
<__CFRunLoopRun+968>
<CFRunLoopRunSpecific+572>
<GSEventRunModal+160>
<-[UIApplication _run]+868>
<UIApplicationMain+124>
<OUTLINED_FUNCTION_70+500>
<OUTLINED_FUNCTION_70+148>
<OUTLINED_FUNCTION_2+92>
<$s4test0A3AppV5$mainyyFZ+40>
<main+12>
102221544
1022ca0e0 487a800000000000
看来貌似是 CoreGraphics 在绘制圆角矩形时收到了某个“调皮捣蛋”的实参,我不知道这是否为 SwiftUI 中的一个 Bug,因为在示例代码中我们并没有任何明显“违规的行为”。
想要继续深入探索的小伙伴们可以在 Xcode 中设置如下符号断点:
[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadii:segments:smoothPillShapes:]
然后运行 App,等进入中断后分析通用寄存器组,看一下到底哪个参数的值是“罪魁祸首”:
这里限于篇幅就不进一步展开讨论了。
其实,我们高度怀疑这个错误不是由户输入而是用户在 TextField 上长按弹出系统选择菜单所引起的。这就意味着它作为一个系统层面上的 Bug 的嫌疑又大了不少。
这个问题在未来系统中是否会自行消失呢,让我们拭目以待吧!
关于该“错误”的进一步讨论,请小伙伴们移步 Apple 开发者官方论坛一探究竟:
- Invalid Numeric Value (NaN) Error in SwiftUI’s TextField on Long-Press
总结
在本篇博文中,我们介绍了 Xcode 15 运行 SwiftUI 代码出现“has passed an invalid numeric value to CoreGraphics”警告这一现象,并根据提示向小伙伴们演示了如何在 Xcode 中为 App 添加运行时的环境变量。
感谢观赏,再会!😎