SwiftUI遍历协议数组报错:要求Content遵循AccessibilityRotorContent
问题:SwiftUI遍历协议数组渲染视图时的类型错误
尝试遍历协议类型数组,让每个元素渲染对应视图。协议包含返回any View的buildView()方法,但调用时触发如下错误:
Static method 'buildExpression' requires that 'Content' conform to 'AccessibilityRotorContent'
相关代码
import UIKit import SwiftUI import PlaygroundSupport protocol ViewItem: AnyObject, Hashable, Identifiable { var id: UUID { get } func buildView() -> any View } class ViewOne: ViewItem { let id: UUID = UUID() func buildView() -> any View { Text("View one") } static func == (lhs: ViewOne, rhs: ViewOne) -> Bool { lhs.id == rhs.id } func hash(into hasher: inout Hasher) { hasher.combine(id) } } class ViewTwo: ViewItem { let id: UUID = UUID() func buildView() -> any View { Text("View two") } static func == (lhs: ViewTwo, rhs: ViewTwo) -> Bool { lhs.id == rhs.id } func hash(into hasher: inout Hasher) { hasher.combine(id) } } struct ContentView: View { let viewItems: [any ViewItem] var body: some View { VStack { ForEach(viewItems, id: \.id) { viewItem in viewItem.buildView() <------------------ ERROR HERE } } } }
解决方案
错误根源是SwiftUI的视图DSL无法直接处理any View这种存在类型,需要将其转换为具体的View类型(比如AnyView)。有两种修改方式:
方式一:修改协议返回类型为AnyView
直接把协议的buildView()方法返回值改为AnyView,实现类中用AnyView包裹视图:
protocol ViewItem: AnyObject, Hashable, Identifiable { var id: UUID { get } func buildView() -> AnyView } class ViewOne: ViewItem { // ... 其他代码不变 func buildView() -> AnyView { AnyView(Text("View one")) } } class ViewTwo: ViewItem { // ... 其他代码不变 func buildView() -> AnyView { AnyView(Text("View two")) } } // ContentView中无需修改,直接调用即可 struct ContentView: View { let viewItems: [any ViewItem] var body: some View { VStack { ForEach(viewItems, id: \.id) { viewItem in viewItem.buildView() } } } }
方式二:调用时用AnyView包裹返回值
如果不想修改协议,在ContentView的ForEach中,将any View转换为AnyView:
struct ContentView: View { let viewItems: [any ViewItem] var body: some View { VStack { ForEach(viewItems, id: \.id) { viewItem in AnyView(viewItem.buildView()) } } } }
两种方式本质都是通过AnyView完成类型擦除,让SwiftUI能识别并渲染视图。
内容的提问来源于stack exchange,提问作者Mr.P
相关产品推荐
相关产品推荐

