为何遵循CaseIterable的协议的allCases不满足RandomAccessCollection要求?
SwiftUI ForEach 编译错误:要求'C.C.AllCases'遵循'RandomAccessCollection'的原因与解决方法
错误原因
CaseIterable协议仅要求关联类型AllCases遵循Collection,并没有强制它必须是RandomAccessCollection——虽然Swift标准库中大多数枚举自动生成的allCases是Array(Array确实遵循RandomAccessCollection),但在泛型上下文里,编译器无法推断所有遵循Category的类型的AllCases都满足RandomAccessCollection约束。而你使用的ForEach(_:content:)初始化器,要求数据源同时遵循RandomAccessCollection和Identifiable,因此触发编译错误。
解决方法
方法一:约束Category协议的AllCases为RandomAccessCollection
直接修改Category协议,强制其AllCases关联类型遵循RandomAccessCollection,这样所有遵循该协议的类型都会满足ForEach的要求:
protocol Component { associatedtype C: Category } protocol Category: Identifiable, CaseIterable where AllCases: RandomAccessCollection { var name: String { get } } struct ComponentsView<C: Component>: View { var body: some View { ForEach(C.C.allCases) { category in Text(category.name) } } }
方法二:使用ForEach的带id参数的初始化器
如果不想修改Category协议,可以改用ForEach的另一个初始化器ForEach(_:id:content:),它只要求数据源是Collection类型,不需要RandomAccessCollection:
protocol Component { associatedtype C: Category } protocol Category: Identifiable, CaseIterable { var name: String { get } } struct ComponentsView<C: Component>: View { var body: some View { ForEach(C.C.allCases, id: \.id) { category in Text(category.name) } } }
方法三:在ComponentsView的泛型约束中补充条件
也可以在ComponentsView的泛型参数上直接约束C.C.AllCases遵循RandomAccessCollection,仅针对当前视图生效:
protocol Component { associatedtype C: Category } protocol Category: Identifiable, CaseIterable { var name: String { get } } struct ComponentsView<C: Component>: View where C.C.AllCases: RandomAccessCollection { var body: some View { ForEach(C.C.allCases) { category in Text(category.name) } } }
内容的提问来源于stack exchange,提问作者christophriepe
相关产品推荐
相关产品推荐

