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)
}
}
Post
Replies
Boosts
Views
Activity
Ok, so I erase all content and re installed simulator - it fixed it!