首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >初始化@ObservedObject内部视图时内存泄漏

初始化@ObservedObject内部视图时内存泄漏
EN

Stack Overflow用户
提问于 2019-11-17 05:12:48
回答 3查看 2.1K关注 0票数 6

我有一个ViewModel类,它是一个ObservableObject,我在初始化它的对应视图时初始化它。如果我在视图中有任何绑定到ViewModel,那么ViewModel就会被泄露。

例如,如果我在工作表中显示上述视图,则每次显示工作表时,都会分配一个新的引用,当工作表被取消时,它不会被释放。参考计数一直在增长,就像我提交纸张的次数一样。

我是遗漏了什么,还是@ObservedObject属性包装器不应该以这种方式使用?

这是一个简单的例子,展示了这个问题。从未为deinit调用ViewModel函数

代码语言:javascript
运行
复制
struct NewContactView: View {

    class ViewModel: ObservableObject {

        @Published var firstName = ""
        @Published var lastName = ""
        @Published var email = ""
        @Published var phoneNumber = ""

        init() {
            print("INIT")
        }

        deinit {
            print("DEINIT")
        }

    }

    @ObservedObject private var viewModel = ViewModel()

    var didCreateNewContact: (Contact) -> Void = { _ in }

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Names")) {
                    TextField("First Name", text: $viewModel.firstName)
                    TextField("Last Name", text: $viewModel.lastName)
                }

                Section(header: Text("Details")) {
                    TextField("Email", text: $viewModel.email)
                    TextField("Phone Number", text: $viewModel.phoneNumber)
                }

                Button(action: {}) {
                    Text("Save")
                }
            }
        }
    }
}

编辑:添加了显示工作表的代码

代码语言:javascript
运行
复制
struct ContactsListView: View {

    @EnvironmentObject var contactStore: ContactStore

    @State private var isCreatingNewContact = false

    var body: some View {

            List(contactStore.contacts) { contact in
                ContactListItem(contact: contact)
            }
            .navigationBarItems(trailing: Button(action: { self.isCreatingNewContact = true }) {
                Image(systemName: "plus")
            })


            .sheet(isPresented: $isCreatingNewContact) {
                NewContactView(didCreateNewContact: self.createNewContactHandler)
        }
    }


    private func createNewContactHandler(_ contact: Contact) {
        contactStore.contacts.append(contact)
        isCreatingNewContact = false
    }

}

编辑2:内存图截图

编辑3:奇怪的是,用VStack替换表单视图可以消除漏洞。如果我使用List视图而不是VStack,泄漏就会回来.

EN

回答 3

Stack Overflow用户

发布于 2021-08-11 18:10:25

使用@StateObject,以便它只插入一次,用于iOS 14

永远不要这样做:@ create私有var viewModel = ViewModel(),它将一直创建视图模型。您需要在应用程序开始时创建该对象,并将其传递到不能重新创建的位置,或者可以在某些视图中创建,因为仪表板取决于应用程序结构。

票数 2
EN

Stack Overflow用户

发布于 2019-11-17 11:48:21

看上去没有漏水。这是我的视图设置(添加标题以便于参考-代码是在解释之后)。

驶离

User Setup -> Contact Related -> Add Contact

然后返回到主屏幕User Setup,然后导航到下一个屏幕,释放先前创建的视图模型实例。注意:我在模型中添加了唯一的id,当模型被输入和退出时,它会打印id。

这让我相信,当正在使用它的观点被发布时,被观察到的模型就不会被发现。Swift运行时控制何时应该发布可观察的模型。另外,当我对废弃的内存进行分析时,我没有看到内存增长的任何增长。另外,当先前的视图模型实例被释放时,内存中有一个dip,这证明了此时它正在被释放。

代码语言:javascript
运行
复制
struct ContentView: View {
    var body: some View {
        
        NavigationView {
        VStack {
             NavigationLink(destination: ContactRelated() ) {
                 Text("Contact Related")
             }
             Spacer()
        }
        .navigationBarTitle("User Setup")
        }
    }
}
代码语言:javascript
运行
复制
struct ContactRelated: View {
        
    var body: some View {
    
        VStack {
             NavigationLink(destination: NewContactView() ) {
                 Text("Add New Contact")
             }
             Spacer()
        }
        .navigationBarTitle("Contact")
    }
}
代码语言:javascript
运行
复制
struct NewContactView: View {
    
    class ViewModel: ObservableObject {
        
        var id = UUID()
        
        @Published var firstName = ""
        @Published var lastName = ""
        @Published var email = ""
        @Published var phoneNumber = ""
        
        init() {
            print(">>>init \(id)")
        }
        
        deinit {
            print(">>>deinit \(id)")
        }
        
    }
    
    @ObservedObject private var viewModel = ViewModel()
    
    //var didCreateNewContact: (Contact) -> Void = { _ in }
    
    var body: some View {
        
        Form {
            
            Section(header: Text("Names")) {
                TextField("First Name", text: $viewModel.firstName)
                TextField("Last Name", text: $viewModel.lastName)
            }
            
            Section(header: Text("Details")) {
                TextField("Email", text: $viewModel.email)
                TextField("Phone Number", text: $viewModel.phoneNumber)
            }
            
            Button(action: {}) {
                Text("Save")
            }
        }
    .navigationBarTitle("Add Contact")
        
    }
}

通常,我不会在结构中添加可观察视图模型的定义。

票数 1
EN

Stack Overflow用户

发布于 2020-01-01 13:05:00

好像是个虫子。使用ScrollView代替列表对我有效。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58897709

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档