SwiftUI 中 ForEach 结构的最后一个参数的函数类型是啥?

Posted

技术标签:

【中文标题】SwiftUI 中 ForEach 结构的最后一个参数的函数类型是啥?【英文标题】:What is the function type of the last parameter of the ForEach struct from SwiftUI?SwiftUI 中 ForEach 结构的最后一个参数的函数类型是什么? 【发布时间】:2021-04-26 06:05:23 【问题描述】:

上下文:我正在关注https://developer.apple.com/tutorials/swiftui/ 上的教程来了解 Swift 和 ios

在学习 Swift 中的闭包表示法时,我想编写我遇到的闭包的扩展版本。

ForEach(filteredLandmarks) 
  landmark in
      NavigationLink(destination: LandmarkDetail(landmark: landmark)) 
        LandmarkRow(landmark: landmark)
    

第一个代码 sn-p 效果很好。

根据我对尾随闭包的理解,ForEach 结构的最后一个参数所需的函数类型暗示了闭包定义的函数的类型,因此我们不需要明确说明闭包定义的函数的类型,并且仅隐式引用它的唯一参数landmark。但是如果我想显式定义它的类型是什么?

以下是我的尝试,它在 Xcode 中产生错误

协议类型'View'的值不能符合'View';只有结构/枚举/类类型可以符合协议

ForEach(filteredLandmarks) 
  (landmark: Landmark) -> View in
      NavigationLink(destination: LandmarkDetail(landmark: landmark)) 
        LandmarkRow(landmark: landmark)
    

我知道landmark 的类型是Landmark,因为删除-> View 效果很好。所以真的,我只需要知道返回类型是什么?

【问题讨论】:

【参考方案1】:

你打电话给this initialiser:

init(_ data: Data, content: @escaping (Data.Element) -> Content)

(当Data符合RandomAccessCollectionIDData.Element.IDContent符合ViewData.Element符合Identifiable时可用。)

如您所见,闭包应该返回Content。什么是Content

ForEach其实是泛型类型,DataContent其实是ForEach的泛型类型参数:

struct ForEach<Data, ID, Content> 
    where Data : RandomAccessCollection, ID : Hashable

这意味着可以决定Content是什么。

使用-&gt; View 不起作用,因为要使该初始化程序可用,Content 必须符合ViewView does not conform to View,所以你不能这样做。

在您的代码中,您返回一个NavigationLink,这确实是ForEachContent 类型。你应该这样做:

(landmark: Landmark) -> NavigationLink in

然而,问题是,NavigationLink 也是通用的!你必须指定它的泛型参数!

destination 参数的类型是第二个泛型参数,你在尾随闭包中返回的视图是它的第一个泛型参数。假设 LandmarkDetailLandmarkRow 不是通用的,您需要这样做:

(landmark: Landmark) -> NavigationLink<LandmarkRow, LandmarkDetail> in

请注意,在编写 SwiftUI 时,大多数情况下无法分析闭包返回什么类型。假设你这样做了:

ForEach(filteredLandmarks) 
  landmark in
      NavigationLink(destination: LandmarkDetail(landmark: landmark)) 
        LandmarkRow(landmark: landmark).padding()
    

相反,我们将无法知道NavigationLink 的第一个泛型参数的确切类型,因为padding 返回opaque type 的some View。请注意,您也可以在闭包返回类型中执行此操作:

(landmark: Landmark) -> some View in

【讨论】:

太棒了!我很难找到我正在搜索的任何东西的 init 文档,因为它出现在我没想到的示例之后。我不会说“不可能对闭包返回的类型进行这种分析”。返回的不透明类型的示例非常有用且信息丰富,但这正是返回的类型,因此这种分析绝对是可能的,只需使用不透明类型,而不是常规类型,如您所说。也许说这样对闭包返回什么类型的分析比较模棱两可。【参考方案2】:

发布后不久就想通了,这很有趣。

问题有答案,因为闭包是返回一些东西,所以我们只需要知道返回的是什么类型。

有问题的关闭返回一个NavigationLink

NavigationLink

来自docs。

NavigationLink 的 Destination 参数被明确标识为 LandmarkDetail 对象。 Label 参数由尾随闭包定义。这是答案。

ForEach(filteredLandmarks) 
  (landmark: Landmark) -> NavigationLink<LandmarkRow, LandmarkDetail> in
      NavigationLink(destination: LandmarkDetail(landmark: landmark)) 
        LandmarkRow(landmark: landmark)
    

【讨论】:

以上是关于SwiftUI 中 ForEach 结构的最后一个参数的函数类型是啥?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:删除 ForEach 中的最后一行

SwiftUI:删除 ForEach 中的最后一行

SwiftUI:如何使用 ForEach 循环使用各种代码的各种结构?

SwiftUI - 更改 ForEach 中的结构数据集?

SwiftUI - 在 ForEach 中获取 TextField 数组

SwiftUI 在 Foreach 中获得位置