Post

Replies

Boosts

Views

Activity

Reply to Proper initialization - views, dependencies, laoder and viewcontroller
I also have the Startupmanager that checks for update check local stored date against the server for not re fetch unless we need to eg. import SwiftUI class StartupManager { private let userDetailsRepository: UserDetailsRepository private let jobRepository: any JobRepositoryProtocol private let authManager: AuthenticationManager private let lastUpdateRepository: LastUpdateRepository private var cancellables = Set<AnyCancellable>() private var hasFetchedUserDetails = false private var userDetailsFetched = false private var lastUpdateFetched = false private var initialJobsFetched = false @Published var startupComplete = false init(userDetailsRepository: UserDetailsRepository, jobRepository: any JobRepositoryProtocol, authManager: AuthenticationManager, lastUpdateRepository: LastUpdateRepository) { self.userDetailsRepository = userDetailsRepository self.jobRepository = jobRepository self.authManager = authManager self.lastUpdateRepository = lastUpdateRepository } deinit { cancellables.forEach { $0.cancel() } } private func checkStartupComplete() { let isComplete = userDetailsFetched && (lastUpdateFetched || initialJobsFetched) if isComplete && !startupComplete { startupComplete = true } } @MainActor private func fetchInitialJobs() { lastUpdateRepository.logCurrentUpdateStatus() if !userDetailsFetched { fetchUserDetails { [weak self] in Task { @MainActor in guard let self = self else { return } self.performJobFetch() } } } else { performJobFetch() } } @MainActor private func performJobFetch() { jobRepository.fetchJobsWithUserData(limit: 10, offset: 0) .sink(receiveCompletion: { [weak self] completion in guard let self = self else { return } switch completion { case .finished: self.initialJobsFetched = true self.checkStartupComplete() case .failure(let error): self.initialJobsFetched = true self.checkStartupComplete() } }, receiveValue: { [weak self] jobs in self?.initialJobsFetched = true }) .store(in: &cancellables) } private func fetchUserDetails(completion: @escaping () -> Void) { userDetailsRepository.fetchUserDetails() userDetailsRepository.$userDetails .dropFirst() .prefix(1) .sink { [weak self] userDetails in guard let self = self else { return } if userDetails != nil { self.userDetailsFetched = true self.checkStartupComplete() completion() } else { self.userDetailsFetched = true self.checkStartupComplete() completion() } } .store(in: &cancellables) } private func fetchLastUpdateSequentially(hasPerformedInitialFetch: Bool) { if !hasPerformedInitialFetch { fetchMaxLastUpdate { [weak self] in guard let self = self else { return } Task { @MainActor in self.fetchInitialJobs() } } } else { setupNeedsUpdateObserver { [weak self] in guard let self = self else { return } self.fetchNeedsUpdate() } } } private func fetchMaxLastUpdate(completion: @escaping () -> Void) { lastUpdateRepository.fetchMaxLastUpdate() .sink(receiveCompletion: { [weak self] completionStatus in guard let self = self else { return } switch completionStatus { case .finished: UserDefaults.standard.set(true, forKey: "hasPerformedInitialFetch") self.lastUpdateFetched = true self.checkStartupComplete() completion() case .failure(let error): self.lastUpdateFetched = true self.checkStartupComplete() completion() } }, receiveValue: { maxLastUpdate in }) .store(in: &cancellables) } private func setupNeedsUpdateObserver(completion: @escaping () -> Void) { lastUpdateRepository.$needsUpdate .dropFirst() .sink { [weak self] needsUpdate in guard let self = self else { return } if needsUpdate { Task { @MainActor in self.fetchInitialJobs() } } } .store(in: &cancellables) completion() } private func fetchNeedsUpdate() { lastUpdateRepository.fetchNeedsUpdate() .sink(receiveCompletion: { [weak self] completion in guard let self = self else { return } switch completion { case .finished: self.lastUpdateFetched = true self.checkStartupComplete() case .failure(let error): self.lastUpdateFetched = true self.checkStartupComplete() } }, receiveValue: { needsUpdateResult in }) .store(in: &cancellables) } @MainActor func start() { authManager.$isAuthenticated .receive(on: DispatchQueue.main) .sink { [weak self] isAuthenticated in guard let self = self else { return } if isAuthenticated && !self.hasFetchedUserDetails { self.hasFetchedUserDetails = true self.fetchUserDetails { [weak self] in guard let self = self else { return } let hasPerformedInitialFetch = UserDefaults.standard.bool(forKey: "hasPerformedInitialFetch") self.fetchLastUpdateSequentially(hasPerformedInitialFetch: hasPerformedInitialFetch) } } } .store(in: &cancellables) } }
1w