从列表中删除的视图被泄露 [英] Views removed from a List get leaked

查看:20
本文介绍了从列表中删除的视图被泄露的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下示例显示了 List 内的视图 (MyView).轻敲时,它会被完全移除.但是,它的内存永远不会被释放.

The following example shows a view (MyView), inside a List. When tapped, it is removed completely. However, its memory is never released.

这是显而易见的,但事实上 MyView 有一个 SomeClass 类型的属性,它的 deinit 从未被调用.但是,如果在 List 之外取出,视图会被正确处理.

This is made evident but the fact that MyView has a property of type SomeClass, and its deinit is never called. However, if taken outside the List, the view is properly disposed.

这是另一个错误吗?

import SwiftUI

struct ContentView : View {
    @State private var showView = true

    var body: some View {
        VStack {
            List {
                if showView {
                    MyView().tapAction {
                        self.showView.toggle()
                    }
                }
            }
        }
    }
}

struct MyView: View {
    private var myVar = SomeClass()

    var body: some View {
        Text("Tap me to Remove!")
    }
}

class SomeClass {
    init() { }

    deinit {
        print("deinit SomeClass")
    }
}

然而,在这种情况下,deinit 被正确调用.唯一的区别是这里我不使用 List.

In this case, however, the deinit is called properly. The only difference is here I do not use List.

struct ContentView : View {
    @State private var showView = true

    var body: some View {
        VStack {
            if showView {
                MyView().tapAction {
                    self.showView.toggle()
                }
            }
        }
    }
}

推荐答案

实际上这不是一个错误.List 的工作方式不同(有点像应用了一些 android 逻辑).由于项目是可重复使用的,并且隐藏/显示操作是列表中非常常见的操作,因此他们决定将项目保留在内存中,以防您决定恢复它(就像 android 处理活动的方式一样).

Actually it's not a bug. List works differently (a little bit like some android logics applied). Since items are reusable and hide/show action is a very common action in the list, they decide to keep items in memory in case that you decide to restore it (Like the way android handles activities).

只有当其他东西试图取代它们时,它们才会被解除初始化.试试这个代码并调查 UUID 以了解自己.我打赌你会对结果感到震惊:

They are get deinit only if something else tries to replace them. Try this code and investigate on UUIDs to see yourself. I bet you will get shocked by the result:

struct ContentView: View {
    @State private var items = [0, 1, 2, 3]

    var body: some View {
        VStack {
            List(items) { id in
                MyView().tapAction {
                    print("Tapped")
                    self.items.removeLast()
                }
            }
        }
    }
}

struct MyView: View {
    private var myVar = SomeClass()

    var body: some View {
        Text("Tap me to Remove!")
    }
}

class SomeClass {
    init() {
        id = UUID().uuidString
        print("Init id: \(id)")
    }

    let id: String

    deinit {
        print("deinit id: \(id)")
    }
}

如您所见,当您从列表中删除某些内容时,令人惊讶的是剩余的项目会被取消.因为那些正在被替换,而不是你要移除的那个.

As you can see, when you remove something from the list, surprisingly the remaining items get deinited instead. Because those are getting replaced, not the one you are removing.

请注意,此行为尚未记录在案,将来可能会发生变化.

Note that this behavior isn't documented (yet) and may change in the future.

这篇关于从列表中删除的视图被泄露的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆