You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
    }
}

关键触发/缓解细节

我测试后发现几个影响问题的关键点:

  1. 只有当文本内容的尺寸达到一定程度时,问题才会显现
  2. 如果expandedExplanation里的三个备选视图(normal/spaceIsTight/scrolling)任意一个被注释,问题就不再出现
  3. 给chevronUp视图添加垂直内边距(比如.padding(.vertical, 10)),可以规避问题
  4. 直接注释掉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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 07:38:10