SwiftUI View中使用if #available(iOS 15, *)导致应用崩溃问题
该问题是iOS 14及更早版本的Swift runtime在处理opaque返回类型(some View)的条件分支时存在底层缺陷,不同分支返回的View类型差异会触发swift_getOpaqueTypeMetadata访问野指针崩溃,和是否使用ViewBuilder、是否封装为View扩展没有直接关联。
以下是两个可用的修复方案:
方案1:显式声明返回类型为AnyView
直接将方法返回值从some View改为AnyView,强制提前完成类型擦除,绕过runtime的类型推断逻辑,修正后的扩展代码如下:
extension View { func listRowModifier(color: Color) -> AnyView { let baseView = self .frame(maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .leading) .background(color) if #available(iOS 15, *) { return AnyView( baseView .listRowSeparatorVisibility(.hidden) .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) ) } else { return AnyView( baseView .listRowInsets(EdgeInsets(top: -1, leading: 0, bottom: -1, trailing: 0)) ) } } }
同时注意你调用方法时没有传入必填的color参数,需要补全调用逻辑:
List { Spacer().frame(height: headerHeight + Theme.unit(2)).listRowModifier(color: .clear) // 替换为你需要的背景色 // 其他列表项 }
方案2:使用@ViewBuilder自动处理类型(推荐)
如果你的Xcode版本≥13.0,可以用@ViewBuilder注解方法,移除手动的AnyView包装,由编译器自动处理条件分支的类型兼容:
extension View { @ViewBuilder func listRowModifier(color: Color) -> some View { let baseView = self .frame(maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .leading) .background(color) if #available(iOS 15, *) { baseView .listRowSeparatorVisibility(.hidden) .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) } else { baseView .listRowInsets(EdgeInsets(top: -1, leading: 0, bottom: -1, trailing: 0)) } } }
该方案不需要手动做类型擦除,代码更简洁,性能也优于手动包装AnyView。
内容的提问来源于stack exchange,提问作者chrysb
相关产品推荐
相关产品推荐

