1

5 秒後に消えるサブビューを含む次の SwiftUI ビューがあります。フェードは、Combine TimePublisher の結果を受け取ることによってトリガーされますがshowRedViewsinkパブリッシャーのシンク ブロックの値を変更すると、メモリ リークが発生します。

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に比較的慣れていないので、ここで何かを台無しにしているか、正しく考えていないことを確認してください. このリークを回避する最善の方法は何ですか?

編集:リークを示すいくつかの写真を追加します。

メモリリーク写真 1

メモリ リーク pic 2

4

2 に答える 2

0

私の推測では、 を保存し、決して削除しないため、漏れていると思いAnyCancellableますsubscriptions

sinkオペレータは を作成しますAnyCancellable。どこかに保存しないと、サブスクリプションは途中でキャンセルされます。しかし、オペレーターSubscribers.Sinkを使用する代わりにサブスクライバーを直接使用すると、管理するsink必要がなくなります。AnyCancellable

    func fadeRedView() {
        Timer.publish(every: 5.0, on: .main, in: .default)
            .autoconnect()
            .prefix(1)
            .subscribe(Subscribers.Sink(
                receiveCompletion: { _ in },
                receiveValue: { _ in
                    withAnimation {
                        showRedView = false
                    }
                }
            ))
    }

しかし、これはまだやり過ぎです。これには結合は必要ありません。イベントを直接スケジュールできます。

    func fadeRedView() {
        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) {
            withAnimation {
                showRedView = false
            }

        }
    }
于 2020-08-12T14:50:19.363 に答える