上下文:我正在学习https://developer.apple.com/tutorials/swiftui/了解Swift和iOS。
在学习Swift中的闭包表示法时,我想写一个我遇到的闭包的扩展版本。
ForEach(filteredLandmarks) {
landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
第一段代码非常有效。
根据我对尾随闭包的理解,作为ForEach
结构的最后一个参数所需的函数类型意味着由闭包定义的函数类型,因此我们不需要显式地说由闭包定义函数的类型,并且只隐式地引用它的唯一参数landmark
。但是,如果我想明确定义它,它的类型是什么?
以下是我的尝试,它在Xcode 中产生错误
协议类型"View"的值不能符合"View";只有结构/枚举/类类型才能符合协议
ForEach(filteredLandmarks) {
(landmark: Landmark) -> View in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
我知道landmark
有一种类型的Landmark
,因为去掉-> View
效果很好。所以说真的,我只需要知道返回类型是什么?
您正在调用此初始化程序:
init(_ data: Data, content: @escaping (Data.Element) -> Content)
(当Data
符合RandomAccessCollection
,ID
为Data.Element.ID
,Content
符合View
,Data.Element
符合Identifiable
时可用。(
正如您所看到的,闭包应该返回Content
。什么是Content
?
ForEach
实际上是一个泛型类型,Data
和Content
实际上是ForEach
:的泛型类型参数
struct ForEach<Data, ID, Content>
where Data : RandomAccessCollection, ID : Hashable
这意味着您可以决定什么是Content
。
使用-> View
不起作用,因为要使该初始化程序可用,Content
必须符合View
。View
不符合View
,所以您不能这样做。
在您的代码中,您将返回一个NavigationLink
,这实际上是ForEach
的Content
类型。你应该做:
(landmark: Landmark) -> NavigationLink in
然而,问题是,NavigationLink
也是通用的!您必须指定其通用参数!
destination
参数的类型是第二个泛型参数,在尾部闭包中返回的视图是它的第一个泛型参数。假设LandmarkDetail
和LandmarkRow
不是通用的,您需要执行以下操作:
(landmark: Landmark) -> NavigationLink<LandmarkRow, LandmarkDetail> in
请注意,在编写SwiftUI时,大多数时候都无法分析闭包返回的类型。假设你做到了:
ForEach(filteredLandmarks) {
landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark).padding()
}
}
相反,我们将无法知道NavigationLink
的第一个泛型参数的确切类型,因为padding
返回some View
的不透明类型。请注意,您也可以在关闭返回类型中这样做:
(landmark: Landmark) -> some View in
在发布后不久就发现了这一点,很有趣。
这个问题有答案,因为闭包返回了一些东西,所以我们只需要知道返回的是什么类型。
有问题的闭包返回NavigationLink
NavigationLink<标签,目的地>其中标签:查看,目的地:查看
。
NavigationLink
的Destination参数被明确地标识为LandmarkDetail
对象。Label参数由尾部闭包定义。答案是这样的。
ForEach(filteredLandmarks) {
(landmark: Landmark) -> NavigationLink<LandmarkRow, LandmarkDetail> in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}