[英]Escaping closure captures mutating 'self' parameter Error in Swift
创建一个简单的纸牌游戏(套装),我在 model 中有一个 function,它将 X 牌放到牌组上。 目前,当我单击交易卡按钮时,它们都会同时显示,因此我添加了计时器,以便它们一个接一个地出现。 这给出了错误“转义闭包捕获变异'self'参数”关于我可以修复什么的任何想法?
mutating func deal(_ numberOfCards: Int) {
for i in 0..<numberOfCards {
Timer.scheduledTimer(withTimeInterval: 0.3 * Double(i), repeats: false) { _ in
if deck.count > 0 {
dealtCards.append(deck.removeFirst())
}
}
}
}
甚至不需要计时器。 您可以将转换与 animation 结合使用以获得所需的效果。 这里的转换是根据卡片的索引延迟的:
class CardModel: ObservableObject {
@Published var cards: [Int] = []
func deal(_ numberOfCards: Int) {
cards += (cards.count ..< (cards.count + numberOfCards)).map { $0 }
}
func clear() {
cards = []
}
}
struct ContentView: View {
@ObservedObject var cardModel = CardModel()
var body: some View {
GeometryReader { geometry in
VStack {
HStack {
ForEach(0 ..< self.cardModel.cards.count, id: \.self) { index in
CardView(cardNumber: self.cardModel.cards[index])
.transition(.offset(x: geometry.size.width))
.animation(Animation.easeOut.delay(Double(index) * 0.1))
}
}
Button(action: { self.cardModel.deal(2) }) {
Text("Deal")
}
Button(action: { self.cardModel.clear() }) {
Text("Clear")
}
}
}
}
}
struct CardView: View {
let cardNumber: Int
var body: some View {
Rectangle()
.foregroundColor(.green)
.frame(width: 9, height: 16)
}
}
或者更简单一点(没有 CardModel):
struct ContentView: View {
@State var cards: [Int] = []
func deal(_ numberOfCards: Int) {
cards += (cards.count ..< (cards.count + numberOfCards)).map { $0 }
}
func clear() {
cards = []
}
var body: some View {
GeometryReader { geometry in
VStack {
HStack {
ForEach(0 ..< self.cards.count, id: \.self) { index in
CardView(cardNumber: self.cards[index])
.transition(.offset(x: geometry.size.width))
.animation(Animation.easeOut.delay(Double(index) * 0.1))
}
}
Button(action: { self.deal(2) }) {
Text("Deal")
}
Button(action: { self.clear() }) {
Text("Clear")
}
}
}
}
}
struct CardView: View {
let cardNumber: Int
var body: some View {
Rectangle()
.foregroundColor(.green)
.frame(width: 9, height: 16)
}
}
请注意,如果您将卡片居中,这种方法可以正常工作,因为之前的卡片也需要移动。 但是,如果您将卡左对齐(使用间隔),则不需要移动的卡会出现 animation 延迟(animation 以尴尬的延迟开始)。 如果您需要考虑这种情况,您需要使新插入的索引部分成为 model 的一部分。
(这可能是在重复 Jack Goossen 所写的内容;go 先看那里,如果不清楚,这可能会给出更多解释。)
这里的核心问题是您似乎将结构视为引用类型。 结构是一个值。 这意味着它的每个持有者都有自己的副本。 如果您将值传递给 Timer,则 Timer 正在改变它自己的该值的副本,它不能是self
。
在 SwiftUI 中,模型通常是引用类型(类)。 它们代表了一种可识别的“事物”,可以观察到并随着时间的推移而变化。 将此类型更改为 class 可能会解决您的问题。 (请参阅 Jack Goossen 的回答,它使用 class 来保存卡片。)
这与 Swift 与 UIKit 的方向相反,其中视图是引用类型,并且鼓励 model 由值类型组成。 在 SwiftUI 中,视图是结构,而 model 通常由类组成。
(使用与 SwiftUI 结合使用,可以将视图和 model 都变成值类型,但这可能超出了您在这里尝试做的事情,如果您还没有研究过组合或反应式编程,那就有点复杂了。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.