SwiftUI infinite loop issue with @Environment(\.verticalSizeClass)

I see SwiftUI body being repeatedly called in an infinite loop in the presence of Environment variables like horizontalSizeClass or verticalSizeClass. This happens after device is rotated from portrait to landscape and then back to portrait mode. The deinit method of TestPlayerVM is repeatedly called. Minimally reproducible sample code is pasted below.

The infinite loop is not seen if I remove size class environment references, OR, if I skip addPlayerObservers call in the TestPlayerVM initialiser.

import AVKit
import Combine

struct InfiniteLoopView: View {
       @Environment(\.verticalSizeClass) var verticalSizeClass
       @Environment(\.horizontalSizeClass) var horizontalSizeClass
    
       @State private var openPlayer = false
       @State var playerURL: URL = URL(fileURLWithPath: Bundle.main.path(forResource: "Test_Video", ofType: ".mov")!)
    
        var body: some View {
           PlayerView(playerURL: playerURL)
              .ignoresSafeArea()
        }
     }

    struct PlayerView: View {
    @Environment(\.dismiss) var dismiss
    
    var playerURL:URL
    @State var playerVM = TestPlayerVM()
    
    var body: some View {
        VideoPlayer(player: playerVM.player)
            .ignoresSafeArea()
            .background {
                Color.black
            }
            .task {
                let playerItem = AVPlayerItem(url: playerURL)
                playerVM.playerItem = playerItem
            }
    }
  }

@Observable
class TestPlayerVM {
     private(set) public var player: AVPlayer = AVPlayer()

     var playerItem:AVPlayerItem? {
        didSet {
            player.replaceCurrentItem(with: playerItem)
        }
    }
    
    private var cancellable = Set<AnyCancellable>()
    
    init() {
        addPlayerObservers()
    }
    
    deinit {
        print("Deinit Video player manager")
        removeAllObservers()
    }
    
    private func removeAllObservers() {
        cancellable.removeAll()
    }
    
  
    private func addPlayerObservers() {
        
        player.publisher(for: \.timeControlStatus, options: [.initial, .new])
            .receive(on: DispatchQueue.main)
            .sink { timeControlStatus in
                print("Player time control status \(timeControlStatus)")
            }
            .store(in: &cancellable)
        
    }
}

@testinstadev

Can you reproduce the issue when you use onReceive(_:perform:) to observe changes instead of Combine

and if you use AVPlayerViewController within a UIViewControllerRepresentable.

@testinstadev , this is due to the poor design of SwiftUI and constant unnecessary reinitializations of Views. And also Observation. Try to add @ObservationIgnored to playerItem and cancellable:

@ObservationIgnored
var playerItem:AVPlayerItem? { ...

@ObservationIgnored
private var cancellable = Set<AnyCancellable>()
SwiftUI infinite loop issue with @Environment(\.verticalSizeClass)
 
 
Q