gpt4 book ai didi

ios - 如何避免此 SwiftUI + Combine Timer Publisher 引用周期/内存泄漏?

转载 作者:行者123 更新时间:2023-12-01 18:34:14 42 4
gpt4 key购买 nike

我有以下 SwiftUI View ,其中包含一个在五秒后消失的 subview 。淡入淡出是通过接收 Combine TimePublisher 的结果触发的,但是更改 sink 发布者的接收器 block 中的 showRedView 的值会导致内存泄漏。

import Combine
import SwiftUI

struct ContentView: View {
@State var showRedView = true

@State var subscriptions: Set<AnyCancellable> = []

var body: some View {
ZStack {
if showRedView {
Color.red
.transition(.opacity)
}
Text("Hello, world!")
.padding()
}
.onAppear {
fadeRedView()
}
}

func fadeRedView() {
Timer.publish(every: 5.0, on: .main, in: .default)
.autoconnect()
.prefix(1)
.sink { _ in
withAnimation {
showRedView = false
}
}
.store(in: &subscriptions)
}
}

我认为这是通过 AnyCancellable 集合以某种方式在幕后进行管理的。我对 SwiftUI 和 Combine 比较陌生,所以我肯定是在这里搞砸了一些事情或者没有正确考虑它。避免这种泄漏的最佳方法是什么?

编辑:添加一些显示泄漏的图片。

Memory leak pic 1

Memory leak pic 2

最佳答案

View 应该被认为是描述 View 的结构,以及它如何对数据使用react。它们应该是小型的、单一用途的、易于初始化的结构。它们不应该持有具有自己生命周期的实例(例如保持发布者订阅)——那些属于 View 模型。

class ViewModel: ObservableObject {
var pub: AnyPublisher<Void, Never> {
Timer.publish(every: 2.0, on: .main, in: .default).autoconnect()
.prefix(1)
.map { _ in }
.eraseToAnyPublisher()
}
}

并使用 .onReceive 对 View 中发布的事件作出 react :

struct ContentView: View {
@State var showRedView = true

@ObservedObject vm = ViewModel()

var body: some View {
ZStack {
if showRedView {
Color.red
.transition(.opacity)
}
Text("Hello, world!")
.padding()
}
.onReceive(self.vm.pub, perform: {
withAnimation {
self.showRedView = false
}
})
}
}

因此,似乎是通过上述安排,带有 prefix 发布者链的 TimerPublisher 导致了泄漏。它也不是适合您的用例的发布者。

以下实现了相同的结果,没有泄漏:

class ViewModel: ObservableObject {
var pub: AnyPublisher<Void, Never> {
Just(())
.delay(for: .seconds(2.0), scheduler: DispatchQueue.main)
.eraseToAnyPublisher()
}
}

关于ios - 如何避免此 SwiftUI + Combine Timer Publisher 引用周期/内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63321923/

42 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com