[英]How do I read a User's Firestore Map to a Swift Dictionary?
I have my user struct with has a dictionary of all their social medias.我有我的用户结构,其中包含他们所有社交媒体的字典。
struct User: Identifiable {
var id: String { uid }
let uid, email, name, bio, profileImageUrl: String
let numSocials, followers, following: Int
var socials: [String: String]
init(data: [String: Any]) {
self.uid = data["uid"] as? String ?? ""
self.email = data["email"] as? String ?? ""
self.name = data["name"] as? String ?? ""
self.bio = data["bio"] as? String ?? ""
self.profileImageUrl = data["profileImageURL"] as? String ?? ""
self.numSocials = data["numsocials"] as? Int ?? 0
self.followers = data["followers"] as? Int ?? 0
self.following = data["following"] as? Int ?? 0
self.socials = data["socials"] as? [String: String] ?? [:]
}
}
The idea is for socials (the dictionary), to be dynamic, since users can add and remove social medias.这个想法是为了社交(字典)是动态的,因为用户可以添加和删除社交媒体。 Firestore looks like this: Firestore 看起来像这样:
The dictionary is initialized as empty.字典初始化为空。 I have been able to add elements to the dictionary with this function:我已经能够使用这个 function 向字典中添加元素:
private func addToStorage(selectedMedia: String, username: String) -> Bool {
if username == "" {
return false
}
guard let uid = FirebaseManager.shared.auth.currentUser?.uid else {
print("couldnt get uid")
return false
}
FirebaseManager.shared.firestore.collection("users").document(uid).setData([ "socials": [selectedMedia:username] ], merge: true)
print("yoo")
return true
}
However I can't seem to read the firestore map into my swiftui dictionary.但是我似乎无法将 firestore map 读入我的 swiftui 字典。 I want to do this so that I can do a ForEach loop and list all of them.我想这样做,以便我可以执行 ForEach 循环并列出所有这些。 If the map is empty then the list would be empty too, but I can't figure it out.如果 map 为空,则列表也为空,但我无法弄清楚。
Just in case, here is my viewmodel.以防万一,这是我的视图模型。
class MainViewModel: ObservableObject {
@Published var errorMessage = ""
@Published var user: User?
init() {
DispatchQueue.main.async {
self.isUserCurrentlyLoggedOut = FirebaseManager.shared.auth.currentUser?.uid == nil
}
fetchCurrentUser()
}
func fetchCurrentUser() {
guard let uid = FirebaseManager.shared.auth.currentUser?.uid else {
self.errorMessage = "Could not find firebase uid"
print("FAILED TO FIND UID")
return
}
FirebaseManager.shared.firestore.collection("users").document(uid).getDocument { snapshot, error in
if let error = error {
self.errorMessage = "failed to fetch current user: \(error)"
print("failed to fetch current user: \(error)")
return
}
guard let data = snapshot?.data() else {
print("no data found")
self.errorMessage = "No data found"
return
}
self.user = .init(data: data)
}
}
}
TLDR: I can't figure out how to get my firestore map as a swiftui dictionary. TLDR:我不知道如何将我的 firestore map 作为 swiftui 字典。 Whenever I try to access my user's dictionary, the following error appears.每当我尝试访问我的用户词典时,都会出现以下错误。 If I force unwrap it crashes during runtime.如果我强制解包它会在运行时崩溃。 I tried to coalesce with "??"我试图合并“??” but I don't know how to make it be the type it wants.但我不知道如何让它成为它想要的类型。
ForEach(vm.user?.socials.sorted(by: >) ?? [String:String], id: \.key) { key, value in
linkDisplay(social: key, handler: value)
.listRowSeparator(.hidden)
}.onDelete(perform: delete)
Please be patient.请耐心等待。 I have been looking for answers through SO and elsewhere for a long time.很长一段时间以来,我一直在通过 SO 和其他地方寻找答案。 This is all new to me.这对我来说都是新的。 Thanks in advance.提前致谢。
This is a two part answer;这是一个分为两部分的答案; Part 1 addresses the question with a known set of socials (Github, Pinterest, etc).第 1 部分通过一组已知的社交网站(Github、Pinterest 等)解决了这个问题。 I included that to show how to map a Map to a Codable.我将其包括在内以展示如何将 map 和 Map 转换为 Codable。
Part 2 is the answer (TL;DR, skip to Part 2) so the social can be mapped to a dictionary for varying socials.第 2 部分是答案(TL;DR,跳到第 2 部分),因此可以将社交映射到不同社交的字典。
Part 1:第1部分:
Here's an abbreviated structure that will map the Firestore data to a codable object, including the social map field.这是一个缩写结构,它将 map Firestore 数据转换为可编码的 object,包括社交字段 map。 It is specific to the 4 social fields listed.它特定于列出的 4 个社会领域。
struct SocialsCodable: Codable {
var Github: String
var Pinterest: String
var Soundcloud: String
var TikTok: String
}
struct UserWithMapCodable: Identifiable, Codable {
@DocumentID var id: String?
var socials: SocialsCodable? //socials is a `map` in Firestore
}
and the code to read that data以及读取该数据的代码
func readCodableUserWithMap() {
let docRef = self.db.collection("users").document("uid_0")
docRef.getDocument { (document, error) in
if let err = error {
print(err.localizedDescription)
return
}
if let doc = document {
let user = try! doc.data(as: UserWithMapCodable.self)
print(user.socials) //the 4 socials from the SocialsCodable object
}
}
}
Part 2:第2部分:
This is the answer that treats the socials
map field as a dictionary这是将socials
map 字段视为字典的答案
struct UserWithMapCodable: Identifiable, Codable {
@DocumentID var id: String?
var socials: [String: String]?
}
and then the code to map the Firestore data to the object然后代码到 map Firestore 数据到 object
func readCodableUserWithMap() {
let docRef = self.db.collection("users").document("uid_0")
docRef.getDocument { (document, error) in
if let err = error {
print(err.localizedDescription)
return
}
if let doc = document {
let user = try! doc.data(as: UserWithMapCodable.self)
if let mappedField = user.socials {
mappedField.forEach { print($0.key, $0.value) }
}
}
}
}
and the output for part 2和第 2 部分的 output
TikTok ogotok
Pinterest pintepogo
Github popgit
Soundcloud musssiiiccc
I may also suggest taking the socials out of the user document completely and store it as a separate collection我可能还建议将社交完全从用户文档中取出并将其存储为一个单独的集合
socials
some_uid
Github: popgit
Pinterest: pintepogo
another_uid
Github: git-er-done
TikTok: dancezone
That's pretty scaleable and allows for some cool queries: which users have TikTok for example.这是相当可扩展的,并允许进行一些很酷的查询:例如,哪些用户拥有 TikTok。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.