Open1

Swift状態管理のミスにより、何度も初期化される問題について

アッキーアッキー

アプリの初期画面に戻るたびに、CounterPresenterが初期化される

onAppearで初期化が起こっている

失敗コード

App.swift

import SwiftUI

@main
struct SampleWatch_Watch_AppApp: App {
    private let exerciseDataUseCase: ExerciseDataUseCase
    private let initialCounter: CounterEntity
    @State private var isShowAleart = false
    @State private var errorMessage: String?
    @StateObject var workoutManager: WorkoutManager = WorkoutManager()
    
    init() {
        AppLogger.shared.logger.debug("App init")
        exerciseDataUseCase = ExerciseDataUseCase(
            repository: ExerciseDataRepository()
        )
        var targetCount: Int = Int()
        
        do {
            if let target = try exerciseDataUseCase.getMaxRecordCount()  {
                targetCount = target
            } else {
                targetCount = 10
            }
        } catch {
            errorMessage = error.localizedDescription
            AppLogger.shared.logger.error("\(error)")
        }
        
        initialCounter = CounterEntity(
            count: 0,
            targetCount: targetCount
        )
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .alert(isPresented: $isShowAleart) {
                    Alert(
                        title: Text(
                            errorMessage ?? "unknow error"
                        )
                    )
                }
                .environmentObject(workoutManager)
                .environmentObject(
                    CounterPresenter(
                        counter: initialCounter,
                        counterUseCase: CounterUseCase(
                            exerciseDataUseCase: ExerciseDataUseCase(
                                repository: ExerciseDataRepository()
                            )
                        )
                    )
                )
                .onAppear() {
                    workoutManager.requestAuthorization()
                }
        }
    }
}

成功したコード

StateObjectとして定義し、initで初期化する

@StateObject var counterPresenter: CounterPresenter

それを、以下のように適用させることで、毎回の初期化は行われなくなる

 .environmentObject(counterPresenter)

要は、状態管理のミスだった


import SwiftUI

@main
struct SampleWatch_Watch_AppApp: App {
    @State private var isShowAleart = false
    @State private var errorMessage: String?
    @StateObject var workoutManager: WorkoutManager = WorkoutManager()
    @StateObject var counterPresenter: CounterPresenter
    
    init() {
        AppLogger.shared.logger.debug("App init")
        
        let exerciseDataUseCase = ExerciseDataUseCase(
            repository: ExerciseDataRepository()
        )
        var targetCount: Int = Int()
        
        do {
            if let target = try exerciseDataUseCase.getMaxRecordCount()  {
                targetCount = target
            } else {
                targetCount = 10
            }
        } catch {
            errorMessage = error.localizedDescription
            AppLogger.shared.logger.error("\(error)")
        }
        
        let initialCounter = CounterEntity(
            count: 0,
            targetCount: targetCount
        )
        
        let counterUseCase = CounterUseCase(exerciseDataUseCase: exerciseDataUseCase)
        
        let presenter = CounterPresenter(
            counter: initialCounter,
            counterUseCase: counterUseCase
        )
        
        _counterPresenter = StateObject(wrappedValue: presenter)
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .alert(isPresented: $isShowAleart) {
                    Alert(
                        title: Text(
                            errorMessage ?? "unknow error"
                        )
                    )
                }
                .onAppear() {
                    workoutManager.requestAuthorization()
                }
                .environmentObject(workoutManager)
                .environmentObject(counterPresenter)
        }
    }
}