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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:37:38