ViewThatFits在iOS模拟器中引发线程问题导致崩溃或警告
ViewThatFits在iOS模拟器中引发线程问题导致崩溃或警告
我最近在iOS模拟器上测试SwiftUI界面时,遇到了ViewThatFits组件的线程安全问题——根据运行环境的不同,它会触发并发警告或者直接导致App崩溃。下面是完整的问题细节和复现信息:
问题触发环境
- Xcode 26.0 beta 5
- Swift 6(启用严格并发检查)
- 最低部署目标:iOS 17.0
- 构建配置:Debug
- 具体表现差异:
- 直接崩溃:运行iOS 26.0 beta 5的iPhone 16模拟器、运行iOS 18.5的iPhone 16模拟器
- 仅触发警告:运行iOS 17.5的iPhone 15模拟器
复现代码
以下代码在文本内容尺寸达到一定程度时会触发问题:
struct ContentView: View { let item1 = "The quick brown fox jumps over the lazy dog." let item2 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." @State private var isExpanded = false enum LayoutHint { case normal case spaceIsTight case scrolling } private func itemList(items: [String], hint: LayoutHint) -> some View { VStack(alignment: .leading, spacing: 9) { ForEach(Array(items.enumerated()), id: \.offset) { _, text in Text(text) .font(.footnote) } } .frame(maxWidth: .infinity, alignment: .leading) .fixedSize(horizontal: false, vertical: true) } private func expandedExplanation(items: [String]) -> some View { ViewThatFits(in: .vertical) { // 注意:如果注释掉这三个视图中的任意一个,问题就会消失 itemList(items: items, hint: .normal) itemList(items: items, hint: .spaceIsTight) ScrollView { itemList(items: items, hint: .scrolling) } } } private var chevronUp: some View { Image(systemName: "chevron.compact.up") .imageScale(.medium) .font(.title) .fontWeight(.semibold) .foregroundStyle(.gray) // 测试发现:如果加上这行垂直内边距,可以规避问题 // .padding(.vertical, 10) .frame(maxWidth: .infinity) } private var expandedContent: some View { VStack(alignment: .leading, spacing: 20) { expandedExplanation(items: [item1, item2]) // 测试发现:如果注释掉这个chevronUp视图,问题就会消失 chevronUp } .padding() } private var collapsedContent: some View { Text("Show expanded") .foregroundStyle(Color(.link)) .padding() .frame(maxWidth: .infinity) } var body: some View { ZStack(alignment: .top) { if isExpanded { expandedContent } else { collapsedContent } } .clipped() .contentShape(.rect) .background { UnevenRoundedRectangle( topLeadingRadius: 0, bottomLeadingRadius: 20, bottomTrailingRadius: 20, topTrailingRadius: 0 ) .fill(Color(.systemGray6)) .ignoresSafeArea(edges: .top) } .onTapGesture { withAnimation(.easeInOut(duration: 0.25)) { isExpanded.toggle() } } .frame(maxHeight: .infinity, alignment: .top) } }
关键触发/缓解细节
我测试后发现几个影响问题的关键点:
- 只有当文本内容的尺寸达到一定程度时,问题才会显现
- 如果
expandedExplanation里的三个备选视图(normal/spaceIsTight/scrolling)任意一个被注释,问题就不再出现 - 给
chevronUp视图添加垂直内边距(比如.padding(.vertical, 10)),可以规避问题 - 直接注释掉
chevronUp视图,问题也会消失
崩溃调用栈
在崩溃场景下,App会抛出如下线程相关的崩溃日志:
#0 0x0000000104986f18 in _dispatch_assert_queue_fail () #1 0x00000001049bc7f8 in dispatch_assert_queue$V2.cold.1 () #2 0x0000000104986ea0 in dispatch_assert_queue () #3 0x0000000258e52678 in _swift_task_checkIsolatedSwift () #4 0x0000000258e93e0c in swift_task_isCurrentExecutorWithFlagsImpl () #5 0x0000000105750504 in closure #1 in closure #1 in ContentView.itemList(items:hint:) () #6 0x00000001057507d4 in thunk for @escaping @callee_guaranteed (@unowned Int, @guaranteed String) -> (@owned Text) () #7 0x00000001da012d50 in closure #1 () -> τ_0_2 in SwiftUI.ForEachState.item(at: τ_0_0.Index, offset: Swift.Int) -> SwiftUI.ForEachState.Item () #8 0x00000001da01d140 in partial apply forwarder for closure #1 () -> τ_0_2 in SwiftUI.ForEachState.item(at: τ_0_0.Index, offset: Swift.Int) -> SwiftUI.ForEachState.Item () #9 0x00000001d9d1cd28 in closure #1 (Swift.UnsafeMutablePointer<SwiftUI.AccessList>) throws -> τ_0_0 in SwiftUI.ObservationCenter._withObservation(do: () throws -> τ_0_0) throws -> (value: τ_0_0, accessList: Swift.Optional<SwiftUI.AccessList>) () #10 0x00000001d96c319c in partial apply forwarder for closure #1 (Swift.UnsafeMutablePointer<SwiftUI.AccessList>) throws -> τ_0_0 in SwiftUI.ObservationCenter._withObservation(do: () throws -> τ_0_0) throws -> (value: τ_0_0, accessList: Swift.Optional<SwiftUI.AccessList>) () #11 0x00000001d985e9f4 in withUnsafePointer () #12 0x00000001da012244 in item () #13 0x00000001da00c850 in forEachItem () #14 0x00000001da01cea8 in function signature specialization of SwiftUI.ForEachList.applyNodes(from: inout Swift.Int, style: SwiftUI._ViewList_IteratorStyle, list: Swift.Optional<SwiftUI._ViewList>, transform: SwiftUI._ViewList_TemporarySublistTransform, to: (inout Swift.Int, SwiftUI._ViewList_IteratorStyle, SwiftUI._ViewList_Node, SwiftUI._ViewList_TemporarySublistTransform) -> Swift.Bool) -> Swift.Bool () #15 0x00000001da0195a8 in protocol witness for SwiftUI.ViewList.applyNodes(from: inout Swift.Int, style: SwiftUI._ViewList_IteratorStyle, list: Swift.Optional<SwiftUI._ViewList>, transform: SwiftUI._ViewList_TemporarySublistTransform, to: (inout Swift.Int, SwiftUI._ViewList_IteratorStyle, SwiftUI._ViewList_Node, SwiftUI._ViewList_TemporarySublistTransform) -> Swift.Bool) -> Swift.Bool in conformance SwiftUI.ForEachList : SwiftUI.ViewList in SwiftUI ()
内容来源于stack exchange
相关产品推荐
相关产品推荐

