Swift 如何修复由复合修饰符+;动画

Swift 如何修复由复合修饰符+;动画,swift,swiftui,Swift,Swiftui,如何修复在动画中使用复合修改器时发生的内存泄漏 在本例中,我们有4个具有动画旋转效果的MySquareView正方形,它们位于ContentView中的ZStack中,ZStack具有缩放修改器。正如您所看到的,随着时间的推移,正在使用的内存不断增加 同样的问题似乎也发生在其他修饰符上。完整示例: import SwiftUI struct MySquare: Identifiable, Hashable { var id = UUID() var offsetX: CGF

如何修复在动画中使用复合修改器时发生的内存泄漏

在本例中,我们有4个具有动画旋转效果的
MySquareView
正方形,它们位于
ContentView
中的ZStack中,ZStack具有缩放修改器。正如您所看到的,随着时间的推移,正在使用的内存不断增加

同样的问题似乎也发生在其他修饰符上。完整示例:

import SwiftUI

struct MySquare: Identifiable, Hashable {
    var id = UUID()
    var offsetX: CGFloat
    var offsetY: CGFloat
}

struct MySquareView: View {
    @State private var rotateSquare = true
    var body: some View {
        Rectangle()
            .fill(Color.purple)
            .frame(width: 30, height: 30)
            .rotationEffect(.degrees(self.rotateSquare ? -25 : 25))
            .onAppear(perform: {
                withAnimation(Animation.easeInOut(duration: 2).repeatForever(autoreverses: true)) {
                    self.rotateSquare.toggle()
                }
            })
    }
}

struct ContentView: View {


    var mySquares = [
        MySquare(offsetX: -40, offsetY: 40),
        MySquare(offsetX: 50, offsetY: -20),
        MySquare(offsetX: -10, offsetY: 80),
        MySquare(offsetX: 110, offsetY: 20)
    ]

    var body: some View {
        VStack {
            ZStack {
                ForEach(mySquares, id: \.self) { mySquare in
                    MySquareView()
                        .offset(x: mySquare.offsetX, y: mySquare.offsetY)
                }
            }
            .scaleEffect(0.8)

        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

这似乎与在ForEach中嵌入变异有关,查看内存图可能涉及列表(也包括列表)。我建议就这一点提出反馈意见

可以通过卸下ForEach来消除:

func square(at offset: Int) -> some View {
    let mySquare = mySquares[offset]
    return MySquareView()
        .offset(x: mySquare.offsetX,
                y: mySquare.offsetY)
}

var body: some View {
    VStack {
        ZStack {
            square(at: 0)
            square(at: 1)
            square(at: 2)
            square(at: 3)
        }
        .scaleEffect(0.8)
    }
}
您还可以通过注入递归AnyView而不是使用ForEach来解决这个问题。可能还有其他类似的聪明解决方案;这可能值得进一步探索,因为失去ForEach和List是非常令人讨厌的

func loopOver<C: Collection, V: View>(_ list: C, content: (C.Element) -> V) -> AnyView
{
    guard let element = list.first else { return AnyView(EmptyView()) }
    return AnyView(Group {
        content(element)
        loopOver(list.dropFirst(), content: content)
    })
}

var body: some View {
    VStack {
        ZStack {
            loopOver(mySquares) { MySquareView().offset(x: $0.offsetX, y: $0.offsetY )}
        }
        .scaleEffect(0.8)
    }
}
func循环(uu列表:C,内容:(C.Element)->V)->AnyView
{
guard let element=list.first-else{return AnyView(EmptyView())}
返回任意视图(组){
内容(要素)
loopOver(list.dropFirst(),内容:content)
})
}
var body:一些观点{
VStack{
ZStack{
loopOver(mySquares){MySquareView().offset(x:$0.offsetX,y:$0.offsetY)}
}
.scaleEffect(0.8)
}
}

(像这样使用AnyView会妨碍各种SwiftUI优化,因此这是最后一种手段,但在这种情况下可能是必要的。)

当您删除切换rotateSquare的调用时,它是否仍然会这样做?@WarrenBurton否,如果您删除切换到rotateSquare,则似乎没有内存泄漏。感谢您的帮助,很高兴知道这与ForEach有关。现在,我已经确保在ForEach循环中应用大多数修改器,而不是在子视图中或ForEach元素之外,并且大多数修改器都可以工作。