len*_*nny 3 xcode swift swiftui
我注意到 XCode 使用 swiftUI 的奇怪行为withAnimation{}。
我创建了以下工作示例:
import SwiftUI
class Block: Hashable, Identifiable {
// Note: this needs to be a class rather than a struct
var id = UUID()
static func == (lhs: Block, rhs: Block) -> Bool {
lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.id)
}
}
struct ContentView: View {
@State private var blocks: [Block]
init() {
var blocks = [Block]()
/// generate some blocks here
blocks.append(Block())
blocks.append(Block())
blocks.append(Block())
self._blocks = State(initialValue: blocks)
}
var body: some View {
VStack {
ForEach(blocks, id: \.self) { block in
BlockRow(block: block) { b in
print("COMMENT THIS LINE OUT") // try commenting out this line -> XCODE won't build anymore
withAnimation {
self.blocks.remove(at: self.blocks.firstIndex(of: b)!)
}
}
}
}
}
}
struct BlockRow: View {
@State var block: Block
var onDelete: (Block) -> Void = {_ in}
var body: some View {
Text("<Block>")
.onTapGesture {
print("Tap block \(block.id)")
self.onDelete(block)
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的示例按预期工作,如果您单击其中一个块,它就会被删除,并且以下块将很好地滑动到空闲位置。
但 XCode 在这里产生警告,我不明白:
调用“withAnimation”的结果未使用
事情变得更加令人困惑:通过事先注释掉 print Stamenet,withAnimation 块/* print("COMMENT THIS LINE OUT") */XCode 将不再构建项目:
未能产生表达诊断;请提交错误报告
这是一个错误还是我的方法完全偏离了道路?
vac*_*ama 11
问题的根源在于self.blocks.remove(at:)返回了您未处理的值。如果您明确忽略该值,那么无论该print语句是否存在,您的代码都会按预期工作。
withAnimation {
_ = self.blocks.remove(at: self.blocks.firstIndex(of: b)!)
}
Run Code Online (Sandbox Code Playgroud)
Swift 有一个功能,即使用一行代码的闭包会返回该语句的值作为闭包的返回值。所以在这种情况下,如果不忽略remove(at:)它的返回值,它会返回a Block,Block然后成为闭包的返回类型withAnimation。
withAnimation定义如下:
func withAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result
Run Code Online (Sandbox Code Playgroud)
它是一个带有闭包的通用函数。该闭包的返回类型决定了通用占位符的类型,而通用占位符又决定了其withAnimation自身的返回类型。
因此,如果您不忽略 的返回类型remove(at:),该withAnimation<Block>函数将返回一个Block.
如果忽略 的返回值remove(at:),则该语句将变成没有返回值的语句(即,它返回()或Void)。因此,withAnimation函数变为withAnimation<Void>并返回Void。
现在,因为当你删除 print 语句时,闭包 toBlockRow只有一行代码,所以它的返回值是单个语句的返回值,现在是Void:
BlockRow(block: block) { b in
withAnimation {
_ = self.blocks.remove(at: self.blocks.firstIndex(of: b)!)
}
}
Run Code Online (Sandbox Code Playgroud)
BlockRow这与闭包期望的类型相匹配onDelete。
在您的原始代码中,该print语句导致闭包BlockRow有两行代码,从而避免了 Swift 使用单行代码来确定闭包返回类型的功能。您确实收到一条警告,表明您没有使用Block从函数返回的withAnimation<Block>。@Asperi 的答案通过将Block返回的分配给withAnimation<Block>来修复该警告_。这与我建议的解决方案具有相同的效果,但它是在更高级别上处理问题,而不是从问题的根源处处理。
为什么编译器不会抱怨您忽略了 的返回值remove(at:)?
remove(at:)明确设计为允许您丢弃返回的结果,这就是为什么您不会收到它返回您未处理的值的警告。
@discardableResult mutating func remove(at i: Self.Index) -> Self.Element
Run Code Online (Sandbox Code Playgroud)
但正如您所看到的,这会导致您遇到令人困惑的结果。您使用时remove(at:)就好像它返回了Void,但实际上它正在返回Block从数组中删除的 。这就会导致导致您的问题的整个事件链。
| 归档时间: |
|
| 查看次数: |
1813 次 |
| 最近记录: |