Layout 迅捷:Can';ForEach循环中的t调用.frame
TL;DR:如何修改Layout 迅捷:Can';ForEach循环中的t调用.frame,layout,foreach,swiftui,Layout,Foreach,Swiftui,TL;DR:如何修改ForEach结构中的内容 下面是一个自包含的游乐场,其中对frame()的调用在普通body方法中是可以的,但在ZStack/ForEach循环中包装时是语法错误 import UIKit import SwiftUI struct Item: Identifiable { var id = UUID() var name: String init(_ name:String) { self.name = name } } let items =
ForEach
结构中的内容
下面是一个自包含的游乐场,其中对frame()
的调用在普通body
方法中是可以的,但在ZStack/ForEach
循环中包装时是语法错误
import UIKit
import SwiftUI
struct Item: Identifiable {
var id = UUID()
var name: String
init(_ name:String) { self.name = name }
}
let items = [
Item("a"), Item("b"), Item("c")
]
struct ContentView: View {
var body: some View {
return Image("imageName")
.resizable()
.frame(width:0, height:0) // This compiles.
}
var body2: some View {
ZStack {
ForEach(items) { item -> Image in // Return type required...
let i = item // ...because of this line.
return Image(i.name)
.resizable() // Parens required.
.frame(width: 0, height: 0) // Compile error.
}
}
}
}
注意行let i=item
。它代表着我的应用程序中执行一些计算的代码。ForEach
闭包不是一个表达式,这一事实导致编译器抱怨
无法推断复杂的闭包返回类型;添加显式类型以消除歧义
这促使我添加了返回类型。但这就引出了这个问题的主题,编译器错误:
无法将“some View”类型的返回表达式转换为返回类型“Image”
frame()
调用的返回值似乎不是Image
,而是ModifiedContent
我发现(多亏了评论者!)我可以通过(以某种方式)将
ForEach
闭包简化为一个表达式来解决这个问题,这使得返回类型变得可推断,然后我可以删除它。这是我唯一的办法吗?现在我要考虑网格。但要消除第一个错误,需要将项与可识别项一致
struct Item: Identifiable {
var id = UUID()
var name: String
var size: CGSize = .zero
}
我还必须编写一个自定义修改器,用于使用该项创建框架。我们可能希望使用CGRect来创建网格,但要想办法搞乱图像的原点
extension View {
func frame(with size: CGSize) -> some View {
frame(width: size.width, height: size.height)
}
}
然后你的身体会像这样
var body: some View {
ZStack {
ForEach(items) { item in
Image(item.name).resizable().frame(with: item.size)
}
}
}
这是这里
ForEach(items) { item -> Image in
您明确指定闭包返回图像
,但帧
返回某些视图
,因此类型不匹配和编译器错误
使用如下,它将工作
ForEach(items) { item in
据我所知,这可能只是Swift的一个限制,类似于或属于这种类型的推理问题: 我的解决方法是向
项
结构添加功能。现在,ForEach
闭包中需要的每个计算都由项
实例提供,与图像
初始值设定项串联,如下所示:
var body3: some View {
ZStack {
ForEach(items) { item in // No return type specified.
// let (width, height) = ... // Remove pre-calculations that
// confused the compiler.
Image(item.name)
.resizable()
.frame(
width : item.width, // All needed data are
height: item.height // provided in closure param.
)
}
}
}
}
我承认这在习惯上更实用,尽管我更喜欢在调用之前选择一些清晰的任务。(如果分配的计算没有副作用,则基本上是SSA样式,应该通过FP气味测试。)
所以我称之为“答案”,甚至是“解决方案”,尽管我仍然可以抱怨那些毫无帮助的错误信息。但这是一个众所周知的问题,比我更聪明的人已经在这个问题上了。物品已经可以识别了。如果不是,则在前面三行中会出现完全不同的编译错误。我忘了提到我正在使用的视图扩展,与您的类似;我更新了问题。为了简化这个问题,我省略了原点变换。从闭包的签名中删除
->图像
(正如您所做的那样)会导致另一个错误:“无法推断复杂的闭包返回类型”,即使没有对框架
的麻烦调用也是如此。我还注意到您在调用resizeable
时忽略了paren。简言之,我认为你的答案无法编译。我在操场上复制了我的问题,并编辑了问题以提供代码。删除了不相关的扩展名。我可以确认1)调用resizeable
时需要参数,2)编译错误仍然存在。但是,请参见我对@Asperi的回复。您的代码和我的代码在闭包的返回类型上有所不同,并且您的版本(省略返回类型)可以满足编译器的需要,而不是我的原始代码。所以你被证明是正确的。这应该是一个很好的线索。我认为要修复项类型的推断,您只需要向项数组添加显式类型。let items:[Item]=[…]请参阅@Asperi的进一步评论。谢谢你激励我使用游乐场。我理解类型不匹配。如果我接受您的建议并在实际代码中删除返回类型,我会得到错误“无法推断复杂的闭包返回类型;添加显式类型以消除歧义”。但是您的建议确实阻止了(简化)游乐场示例中的错误。所以现在我必须弄清楚有什么不同。我重新编辑了这个问题,把重点放在我发现的问题上:当存在多个表达式时,编译器在推断返回类型方面的问题。因此有一个解决方法:重写代码以避免多表达式体。也许这就足够了。