简体   繁体   中英

How to make ForEach loop for a Codable Swift Struct's Dictionary (based on Firestore map)

I am trying to do a ForEach loop that lists all of the social medias a user might have. This would be on a scrollable list, the equivalent of music streaming apps have a list of all the songs you save in your library. The user's social medias list is in reality a dictionary .

My MainViewModel class implements all of the Firebase functionality. See below.

class MainViewModel: ObservableObject {

@Published var errorMessage = ""
@Published var user: User?

init() {
    DispatchQueue.main.async {
        self.isUserCurrentlyLoggedOut = FirebaseManager.shared.auth.currentUser?.uid == nil
    }

    readCodableUserWithMap()
}

@Published var isUserCurrentlyLoggedOut = false

func handleSignOut() {
    isUserCurrentlyLoggedOut.toggle()
    try? FirebaseManager.shared.auth.signOut()
}

func readCodableUserWithMap() {
    guard let uid = FirebaseManager.shared.auth.currentUser?.uid else {
        self.errorMessage = "Could not find firebase uid"
        print("FAILED TO FIND UID")
        return
    }
    
    let userID = uid
    let docRef = FirebaseManager.shared.firestore.collection("users").document(userID)
    docRef.getDocument { (document, error) in
        if let err = error {
            print(err.localizedDescription)
            return
        }

        if let doc = document {
            let user = try! doc.data(as: User.self)
            if let mappedField = user.socials {
                mappedField.forEach { print($0.key, $0.value) }
            }
        }
    }
}
}

readCodableUserWithMap() is supposed to initialize my codable struct, which represents a user. See below.

struct User: Identifiable, Codable {
   @DocumentID var id: String?
   var socials: [String: String]?
   var uid, email, name, bio, profileImageUrl: String?
   var numSocials, followers, following: Int?
}

QUESTION AT HAND: In my Dashboard View, I am trying to have a list of all the social medias a user can have. I can't manage to make a ForEach loop for my user.

I do:

ForEach(vm.user?.socials.sorted(by: >), id: \.key) { key, value in
                    linkDisplay(social: key, handler: value)
                        .listRowSeparator(.hidden)


                }.onDelete(perform: delete)

This gives me the following errors:

  1. Value of optional type '[Dictionary<String, String>.Element]?' (aka 'Optional<Array<(key: String, value: String)>>') must be unwrapped to a value of type '[Dictionary<String, String>.Element]' (aka 'Array<(key: String, value: String)>')

  2. Value of optional type '[String: String]?' must be unwrapped to refer to member 'sorted' of wrapped base type '[String: String]'

I have tried coalescing using?? but that doesn't work, although I assume I am doing something wrong. Force-unwrapping is something I tried but it made the app crash when it was an empty dictionary.

Just in case, here is the database hierarchy: firebase hierarchy

TLDR: HOW can I make a ForEach loop to list all of my user's medias?

You have both vm.user and socials as optionals. The ForEach loop requires non-optionals, so you could try the following approach to unwrap those for the ForEach loop.

    if let user = vm.user, let socials = user.socials {
        ForEach(socials.sorted(by: > ), id: \.key) { key, value in
            linkDisplay(social: key, handler: value)
                .listRowSeparator(.hidden)
        }.onDelete(perform: delete)
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM