0

I'm having a problem with asynchronous data fetch for my ProfileViewModel in order to display all the data in ProfileView. I tried many ways and it ended either in indefinite ProgressView loading or nil error. In the first place I setup sessionStore (authentication state) passing it to ViewModel from my View's .onAppear. Then I would like to fetch firstName and username from Firebase to my ProfileViewModel, which I do in fetchData function which is executed in ProfileView init.

ProfileViewModel:

@MainActor
class ProfileViewModel: ObservableObject {
    @Published var sessionStore: SessionStore?
    private let firestoreManager = FirestoreManager()
    private let firebaseStorageManager = FirebaseStorageManager()
    
    @Published var profile: Profile?
    @Published var profilePicturePhotoURL: URL?
    
    @Published var workouts: [IntervalWorkout]?
    @Published var fetching: Bool = true
    
    init(forPreviews: Bool) {
        [...]
    }
    
    init() {
        [...]
        
        Task {
            try await fetchData()
        }
    }
    
    func setup(sessionStore: SessionStore) {
        self.sessionStore = sessionStore
    }
    
    func fetchData() async throws {
        if sessionStore != nil {
            if sessionStore!.currentUser != nil {
                    print("Fetching Data")
                    
                    let (firstname, username, birthDate, age, country, language, gender, email, profilePictureURL) = try await self.firestoreManager.fetchDataForProfileViewModel(userID: sessionStore!.currentUser!.uid)
                    
                    self.profile = Profile(id: sessionStore!.currentUser!.uid, firstName: firstname, username: username, birthDate: birthDate, age: age, country: country, language: language, gender: gender, email: email, profilePictureURL: profilePictureURL)
                    
                    print(self.profile!.firstName)
                    
                    if profilePictureURL != nil {
                        self.firebaseStorageManager.getDownloadURLForImage(stringURL: profilePictureURL!, userID: sessionStore!.currentUser!.uid) { photoURL in
                             self.profilePicturePhotoURL = photoURL
                            print("Data fetched")
                        }
                    } else {
                        print("Data fetched - no profilePicture")
                    }
                    
                    print("FETCHING: \(self.fetching)")
                    if self.profile != nil {
                        fetching = false
                    }
                
            } else {
                print("Data not fetched - no sessionStore.currentUser")
            }
        } else {
            print("Data not fetched - no sessionStore")
        }
    }
    
    func uploadPhoto(image: UIImage) {
        [...]
    }
    
    func emailAddressChange(oldEmailAddress: String, password: String, newEmailAddress: String, completion: @escaping (() -> ())) {
        [...]
    }
    
    func deleteUserData(completion: @escaping (() -> ())) {
        [...]
    }
}

ProfileView:

struct ProfileView: View {
    @ObservedObject private var profileViewModel = ProfileViewModel()
    @EnvironmentObject private var sessionStore: SessionStore
    @Environment(\.colorScheme) var colorScheme
    
    @State private var image = UIImage()
    
    @State private var shouldPresentAddActionSheet = false
    @State private var shouldPresentImagePicker = false
    @State private var shouldPresentCamera = false
    
    @State private var shouldPresentSettings = false
    
    @State private var tabSelection = 0
    
    init(forPreviews: Bool) {
        if forPreviews {
            self.profileViewModel = ProfileViewModel(forPreviews: true)
        }
    }
    
    var body: some View {
        GeometryReader { geometry in
            let screenWidth = geometry.size.width
            let screenHeight = geometry.size.height
            
            if !self.profileViewModel.fetching {
                ScrollView(.vertical) {
                    HStack {
                        if profileViewModel.profilePicturePhotoURL != nil {
                            AsyncImage(url: profileViewModel.profilePicturePhotoURL!) { image in
                                [...]
                            } placeholder: {
                                [...]
                            }
                        } else {
                            [...]
                        }
                        
                        Spacer(minLength: screenWidth * 0.05)
                        
                        VStack {
                            HStack {
                                Text(profileViewModel.profile != nil ? profileViewModel.profile!.firstName : "Name")
                                    [...]
                                }
                            }
                            .padding(.top, screenHeight * 0.02)
                            
                            HStack {
                                Text(profileViewModel.profile != nil ? profileViewModel.profile!.username : "Username")
                                    .foregroundColor(Color(uiColor: UIColor.lightGray))
                                Spacer()
                            }
                            
                            Spacer()
                        }
                    }
                    .padding()
                    
                    [...]
                }
                [...]
            } else {
                VStack {
                    Spacer()
                    HStack {
                        Spacer()
                        ProgressView("Loading user's data")
                            .progressViewStyle(RingProgressViewStyle())
                        Spacer()
                    }
                    Spacer()
                }
            }
        }
        .onAppear {
            self.profileViewModel.setup(sessionStore: sessionStore)
        }
    }
}

Console output:

Data not fetched - no sessionStore
Data not fetched - no sessionStore
Fetching Data
Data not fetched - no sessionStore
Łukasz
Data fetched - no profilePicture
FETCHING: true
Vader20FF
  • 271
  • 2
  • 9
  • Can you pare this down into a [mre]? – jnpdx Oct 28 '21 at 12:53
  • @jnpdx Honestly, I can't do much more because I do not exactly know where the problem lays - is it because of sessionStore or ProfileViewModel initialization or because of problem with data assigning somewhere. I trimmed the code into the parts that have to be checked in my opinion by someone more experienced than me – Vader20FF Oct 28 '21 at 13:05
  • 2
    There are definitely parts in here that don’t need to be tested (stacks, text elements, unnecessary state variables, etc). It makes it more complicated that you’ve made it not compliance by adding […] all over the place. Try making something that can be copied and pasted into Xcode. The process of doing so might help isolate your error as well. – jnpdx Oct 28 '21 at 13:09
  • @jnpdx While trying to trim the code even more I realized that I could describe my problems better so I created completely new question which can be found here: https://stackoverflow.com/questions/69772487/firebase-auth-problems-with-data-fetching-after-signing-up-and-opening-profilevi – Vader20FF Oct 29 '21 at 17:05

0 Answers0