我在做动画.它有一堆围巾,上面有Lottie动画.CardStack号牌库用于卡片,Lottie号牌用于彩票.

CardStack库中,配置参数设置为显示2张卡(当前和下一张),但尽管如此,只有在视图更改状态时才会释放内存.

内存一直累积到最后一张卡.

相应地,如果100张卡到达,那么就会有麻烦.最重要的是,没有内存泄漏.

我用Lottie库try 了各种加速器,但都没有帮助.

我至少应该朝哪个方向看,以免浪费那么多内存?在其他操作系统上一切正常,所以问题不在动画上.

下面是来自UIViewRepresentable的代码:

struct CustomLottieView: UIViewRepresentable {
    enum LoadingType {
        case url(URL)
        case data(DataResource)
    }
    
    let type: LoadingType
    
    let isPaused: Bool
    
    let card: CardModel?
    
    let animationView = LottieAnimationView()
    
    let transition: BoundCardType?
    
    init(type: LoadingType, isPaused: Bool = false, card: CardModel? = nil, transition: BoundCardType? = nil) {
        self.isPaused = isPaused
        self.type = type
        self.card = card
        self.transition = transition
    }
    
    func makeUIView(context: Context) -> UIView {
        let view = UIView(frame: .zero)
        
        switch type {
        case .url(let url):
            LottieAnimation.loadedFrom(url: url) { animation in
                animationView.animation = animation
                isPaused ? nil : animationView.play()
                animationView.loopMode = .loop
                
                if let skillCardModel = card as? SkillCardModel {
                    animationView.play(marker: String(skillCardModel.currentLevelIndex + 1))
                }
            }
        case .data(let data):
            animationView.animation = .named(data.name, bundle: data.bundle)
            
            if let skillCardModel = card as? SkillCardModel {
                animationView.play(marker: String(skillCardModel.currentLevelIndex + 1))
            }
        }
        
        animationView.contentMode = .scaleAspectFit
        
        animationView.play()
 
        view.addSubview(animationView)
 
        animationView.translatesAutoresizingMaskIntoConstraints = false
        animationView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
        animationView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
 
        return view
    }
 
    func updateUIView(_ uiView: UIView, context: Context) {
        if isPaused {
            context.coordinator.parent.animationView.pause()
        } else {
            if let skillCardModel = card as? SkillCardModel {
                if !context.coordinator.parent.animationView.isAnimationPlaying || animationView.animation == nil {
                    context.coordinator.parent.animationView.play(marker: String(skillCardModel.currentLevelIndex + 1))
                } else {
                    withAnimation {
                        var transitionMarker = ""
                        if let transition = transition {
                            switch transition {
                            case .left:
                                transitionMarker = context.coordinator.parent.animationView.animation?.markerNames.first(where: { $0.contains(">\(skillCardModel.currentLevelIndex + 2)") }) ?? ""
                                context.coordinator.parent.animationView.play(fromMarker: String(skillCardModel.currentLevelIndex + 2), toMarker: transitionMarker, loopMode: .playOnce)
                            case .right:
                                transitionMarker = context.coordinator.parent.animationView.animation?.markerNames.first(where: { $0.contains("\(skillCardModel.currentLevelIndex)>") }) ?? ""
                                context.coordinator.parent.animationView.play(fromMarker: transitionMarker, toMarker: String(skillCardModel.currentLevelIndex + 1), loopMode: .playOnce)
                            }
                        }
                        
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                            context.coordinator.parent.animationView.play(marker: String(skillCardModel.currentLevelIndex + 1), loopMode: .loop)
                        }
                    }
                }
            } else {
                context.coordinator.parent.animationView.play()
            }
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    struct Coordinator {
        var parent: CustomLottieView
    }
}

推荐答案

您正在描述CardStack库的一个特征;它存储所有卡片物品数据模型以及每个关联的视图.即使卡片视图目前没有在屏幕上显示(展开),它仍将存储在内存中.

这是有意义的;视图存储在lazy-loaded property中,加载后将 for each 卡片项目生成一个视图.换句话说,这些视图是一次性生成的,并在卡片堆栈的生命周期内存储.

听起来您更希望CardStack库更像TableView或CollectionView,在需要时动态生成视图,并在它们移出屏幕时销毁它们.这不是CardStack的实现方式.

我建议派生CardStack库,并更改视图的生成和存储方式.您仍然需要 for each 卡片预先生成视图(因为您需要某种视觉效果才能显示在堆栈中),但是直到卡片出现在屏幕上(展开)之前,才需要生成每个卡片的内部内容.当卡片离开屏幕(折叠)时,您可以从内存中删除此内容视图.

Swift相关问答推荐

如何使用RxSwift根据数据数绘制UICollectionView单元格

按变换zoom 在UIView中不起作用

如何在AudioKit中实现自定义音效 node ?

ARRaycast Query和前置摄像头(ARFaceTrackingConfiguration)

SWIFT计划计时器方法在时间间隔后未被调用

文件命名&NumberForMatter+扩展名&:含义?

本地对象的异步/等待引用捕获总是安全的还是理论上不安全?

如何判断一个值是否为 Int 类型

当使用 CGFloat 而不是数字文字时,为什么 node 的位置会发生变化?

如何从另一个 swift 文件中调用函数

将 struct 作为泛型类型传递并访问该泛型类型属性

SwiftUI:异步网络请求后@State 值不更新

ZStack 中的 ProgressView 与 View 的行为不同

不使用 ViewController 时如何显示推送通知的alert 对话框

如何使 SwiftUI Picker 换行文本

调用从 SwiftUI 视图传递到 PageViewController.Coordinator 的函数

异步等待不会在项目中触发,但在 Xcode playground 中工作正常

如何使用 Swift/iOS 为人类书写的笔画制作动画?

如何更改弹出框的大小

iOS/Swift:如何检测 UITextField 上的touch 动作