更新环境对象会使内存随着每次更新而保持增长

时间:2020-08-01 12:33:48

标签: swift macos memory-leaks

我创建了一个新应用,代表了我在实际应用中遇到的类似情况。基本上,我正在更新可观察对象的值,该对象用于呈现UI。并且由于某种原因导致内存在每次迭代中都保持增长。我还注意到,内存增长的数量取决于ContentView中的每秒迭代次数和视图数量/类型。

注意:正在更新的可观察对象是self.infoObj.text = "Counter: \(counter)"

AppDelgate.swift

func applicationDidFinishLaunching(_ aNotification: Notification) {
    infoObj = InfoObj()

    // Create the SwiftUI view that provides the window contents.
    let contentView = ContentView()
        .environmentObject(infoObj)

    // Create the window and set the content view. 
    window = NSWindow(
        contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
        styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
        backing: .buffered, defer: false)
    window.center()
    window.setFrameAutosaveName("Main Window")
    window.contentView = NSHostingView(rootView: contentView)
    window.makeKeyAndOrderFront(nil)
    
    var counter = 0;
    
    DispatchQueue.global(qos: .userInteractive).async {
        while(true) {
            usleep(1000)
            counter += 1
            DispatchQueue.main.sync {
                self.infoObj.text = "Counter: \(counter)"
            }
        }
    }
}

ContentView.swift

struct ContentView: View {
    @EnvironmentObject var infoObj: InfoObj
    
    var body: some View {
        VStack {
            HStack {
                Text("Text 11")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 12")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 13")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 14")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 15")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            Text(infoObj.text)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            HStack {
                Text("Text 21")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 22")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 23")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 24")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 25")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            HStack {
                Text("Text 31")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 32")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 33")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 34")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 35")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            HStack {
                Text("Text 41")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 42")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 43")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 44")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 45")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            HStack {
                Text("Text 51")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 52")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 53")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 54")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 55")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

class InfoObj: ObservableObject {
    @Published var text = "initial"
}

您能帮助我理解这种情况发生的原因吗?我该如何解决呢?另外,为什么代码工具不将其视为内存泄漏?

1 个答案:

答案 0 :(得分:1)

您只是同步地在堆栈上循环执行,因此您会观察到堆栈不断增长(不会作为泄漏的内存处理)。

解决方案是改为进行异步计数器处理并将所有内容移入EnvironmentObject

class InfoObj: ObservableObject {
    private var counter = 0
    @Published var text = "initial" {
        didSet {
            print(">> " + text)   // << used for testing
        }
    }

    func runCounter() {
        counter += 1
        text = "Counter: \(self.counter)"

        // !! There is no sense to update UI with 1 milisecond 
        // (but you can tune interval below as you need)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.05, execute: runCounter)
    }
}

并使用

    // ... other code
    window.contentView = NSHostingView(rootView: contentView)
    window.makeKeyAndOrderFront(nil)

    infoObj.runCounter()      // << here !!    
}
相关问题