I recently started looking into SwiftUI and have run through a few tutorials which recommend swapping views based on state (see the snippet below). However, I noticed while debugging that memory usage slowly creeps up with even the most basic UI. This may just be lack of knowledge but is it wrong to swap views in this sort of manner with SwiftUI?
Version 11.0 (11A420a) - iOS 13
// Memory Leak Test
struct ContentView: View {
@State private var toggle = false
func cycleViews() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.toggle = !self.toggle
self.cycleViews()
}
}
var body: some View {
Group {
if toggle {
ViewA()
} else {
ViewB()
}
}.onAppear {
self.cycleViews()
}
}
}
struct ViewA: View {
var body: some View {
VStack {
Text("Some Content")
Text("Some Content")
Text("Some Content")
Text("Some Content")
Text("Some Content")
}
}
}
struct ViewB: View {
var body: some View {
List {
Text("Some Content")
Text("Some Content")
Text("Some Content")
Text("Some Content")
Text("Some Content")
}
}
}
Xcode's Memory Graph Debugger If you haven't used this yet, it's easy to access while developing. Tapping on the icon will pause your application and generate a graph of the objects with their references to other objects. If there's leaked memory detected, you will see purple icons on the left pane of Xcode.
A memory leak occurs when allocated memory becomes unreachable and the app can't deallocate it. Allowing an allocated-memory pointer to go out of scope without freeing the memory can cause a memory leak. A retain cycle in your app's object graph can also cause a memory leak.
Breaking a retain cycle to prevent memory leak The cycle must exist because it is required, but all the associations cannot be strong. One of them must be weak or unowned. The weak reference is an optional type, which means weak reference will set to nil once the instance it refers to frees from memory.
SwiftUI helps you build great-looking apps across all Apple platforms with the power of Swift — and surprisingly little code. You can bring even better experiences to everyone, on any Apple device, using just one set of tools and APIs.
Your code appears to be perfectly acceptable SwiftUI, and there does appear to be a memory leak somewhere, as switching back and forth (even with a manual Toggle()
instead of the asyncAfter()
call) leads to increasing memory.
I believe this is a bug with List, because if you change the List to another type of view, the issue disappears, and I haven't noticed it when using this same pattern with all other kinds of views.
I'd recommend you file feedback with Apple, and post the feedback number here so others affected can file their own and reference it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With