Search code examples
iosswiftswiftuiavfoundation

SwiftUI view freezes due to Timer object


When I try to update a text in SwiftUI view using Timer and .onReceive(timer) modifier, view freezes.

import SwiftUI
import Combine
import AVFoundation

var globalText: String = "abc"

struct ContentView : View {

    @State private var myText = globalText
    
    let timer = Timer.publish(every: 1, on: .current, in: .default)
                     .autoconnect()

    var body: some View {
        ZStack {
            AVContainer().ignoresSafeArea()
            Text(myText)
                .onReceive(timer) { _ in myText = globalText }
                .font(.largeTitle)
        }
    }
}

struct AVContainer : UIViewRepresentable { ... }

What am I doing wrong?


Solution

  • I recently had a similar problem with my AR app. In your case, you need to declare and instantiate the view in the ContentView struct, and then create its binding variable in the AVContainer struct. I can't explain why the below approach works, but it definitely works – there's no freezing anymore.

    import SwiftUI
    import Combine
    import AVFoundation
    
    var globalText: String = "abc"
    
    struct ContentView : View {    
        @State var yourView = YourView(frame: .zero)
        @State var myText = globalText
        
        let timer = Timer.publish(every: 1, on: .current, in: .default)
                         .autoconnect()
    
        var body: some View {
            ZStack {
                AVContainer(yourView: $yourView).ignoresSafeArea()
                Text(myText)
                    .onReceive(timer) { _ in myText = globalText }
                    .font(.largeTitle)
                VStack {
                    Spacer()
                    Button("Restart App") {
                        self.timer.upstream.connect().cancel()
                        myText = "..."
                    }
                }
            }
        }
    }    
    struct AVContainer : UIViewRepresentable { 
        @Binding var yourView: YourView
        // code here ...
    }