SwiftUI-隐藏LazyVGrid导致内存泄漏

时间:2020-10-31 23:21:20

标签: swift memory-leaks swiftui

我有一个LazyVGrid,它显示了从远程API提取的一些数据。 通过按钮隐藏LazyVGrid时,遇到内存泄漏。仅当内容超出LazyVGrid内部显示的内容时,这种情况才会发生。

enter image description here

我已经为您准备了一些代码来重现此泄漏。 这段代码是否有些夸张,还是在苹果方面有漏洞?也许有解决方法?

import SwiftUI
import Foundation
import Combine

enum FakeAPI {
    static var fakeData: [Result] {
       return [
            Result(id: 1), Result(id: 2), Result(id: 3), Result(id: 4), Result(id: 5),
            Result(id: 6), Result(id: 7), Result(id: 8), Result(id: 9), Result(id: 10),
            Result(id: 11), Result(id: 12), Result(id: 13), Result(id: 14), Result(id: 15),
            Result(id: 16), Result(id: 17), Result(id: 18), Result(id: 19), Result(id: 20),
            Result(id: 21), Result(id: 22), Result(id: 23), Result(id: 24), Result(id: 25),
            Result(id: 26), Result(id: 27), Result(id: 28), Result(id: 29), Result(id: 30)
       ]
    }

    static func fetchData() -> AnyPublisher<[Result], Error> {
        return Just(fakeData)
            .mapError({ $0 as Error })
            .eraseToAnyPublisher()
    }
}

struct Result: Identifiable {
    let id: Int
}

struct ContentView: View {
    @StateObject private var vm: ViewModel = ViewModel()

    let columns = [
        GridItem(.adaptive(minimum: 200), alignment: .top),
        GridItem(.adaptive(minimum: 200), alignment: .top)
    ]

    var body: some View {
        NavigationView {
            ScrollView {
                Button {
                    vm.hide = true
                } label: {
                    Text("Hide")
                }
                if !vm.hide {
                    LazyVGrid(columns: columns) {
                        ForEach(vm.results) { result in
                            Text("\(result.id)")
                                .frame(width: 120, height: 120)
                                .background(Color.red)
                        }
                    }
                }
            }
            .navigationTitle("Grid Memory Leak")
            .onAppear {
                vm.load()
            }
        }
    }
}

final class ViewModel: ObservableObject {
    @Published private(set) var results: [Result] = []
    @Published var hide = false

    private var subscriptions = Set<AnyCancellable>()

    func load() -> Void {
        FakeAPI.fetchData()
            .sink(receiveCompletion: { _ in }, receiveValue: { [weak self] results in
                self?.results = results
            })
            .store(in: &subscriptions)
    }
}

0 个答案:

没有答案