# #ios #swift #firebase #google-cloud-firestore #swiftui
Вопрос:
Я пытаюсь реализовать модель дружбы с firebase и swiftui. В одном из моих представлений, при появлении вызова, я вызываю метод проверки статуса дружбы, как показано ниже:
Редактировать: я сделал isFriend опубликованной переменной, которая должна обновляться следующим образом
class UserViewModel : ObservableObject{
....
//check friendship variabe
@Published var isFriend = 0
func checkFriendRequest(otherUserUID: String) -> Int{
//0 if not found in friend list or friend request
//1 means theyre friends
//2 means that user sent self/me a friend request
print("otherUserUID is (otherUserUID)")
var pendingFriendRequests: [String: Bool] = [:]
self.ref.collection("Users").document(self.uid).getDocument(){
(document, err) in
if let err = err {
print("Error getting documents (err)")
} else {
pendingFriendRequests = document!.data()!["friends"] as! [String : Bool]
print("pendingFriendRequests is (pendingFriendRequests)")
for key in pendingFriendRequests.keys {
if key == otherUserUID{
print("key is (key) and value is (pendingFriendRequests[key])")
if pendingFriendRequests[key] == true {
self.isFriend = 1
}else if pendingFriendRequests[key] == false {
self.isFriend = 2
}
}
}
}
}
return self.isFriend
}
}
В моем коде представления я хотел бы проверить возвращаемое значение этой функции и обновить текст/действие кнопки, которая должна быть в представлении, и это будет выглядеть следующим образом:
struct OtherUser: View {
@StateObject var userData = UserViewModel()
var otherUserUID: String
var otherUserName: String
var otherUserUsername: String
var otherUserPic: String
@Environment(.presentationMode) var present
init(_ otherUserUID: String, _ otherUserName: String, _ otherUserUsername: String, _ otherUserPic: String){
self.otherUserUID = otherUserUID
self.otherUserName = otherUserName
self.otherUserUsername = otherUserUsername
self.otherUserPic = otherUserPic
}
var body: some View {
ZStack(alignment: .top){
Color("Black")
.ignoresSafeArea()
VStack {
if (userData.checkFriendRequest(otherUserUID: otherUserUID)) == 1 {
//button for if returned 1
}else if (userData.checkFriendRequest(otherUserUID: otherUserUID)) == 2 {
//button for if returned 2
}else {
}
}
}
}
}
Однако при появлении представления оно автоматически возвращает 0 без обновления значения после асинхронного вызова firebase. Я искал другие решения и пробовал группы отправки, но, похоже, они не работают. Я понимаю, что это как-то связано с асинхронной природой firebase, но хотел бы получить некоторую помощь, чтобы понять, как это улучшить, чтобы переменная isFriend обновлялась, а затем возвращалась до появления представления. Спасибо за вашу помощь
Комментарии:
1. «…обновляется, а затем возвращается до появления представления» То, о чем вы спрашиваете, невозможно. Что делать, если сеть работает медленно или не подключена? Вид должен зависать/блокироваться? Лучшее, что вы можете сделать, это обновить объект @State или @ObservedObject, который (автоматически) запускает представление для обновления с новыми результатами. Вы не показываете свой код просмотра…
2. Спасибо за ответ, я отредактировал свой код, чтобы включить опубликованный/наблюдаемый объект, но он все равно не работал и возвращает только 0. Я показал свой код представления, который я хотел бы изменить в зависимости от того, возвращает ли он 0, 1 или 2. Спасибо
3. Вызовы Firebase, такие как getDocument (), являются асинхронными. Вы не можете вернуть значение в конце функции. Вместо
if (userData.checkFriendRequest)
того, чтобы вы должны были использоватьif userData.isFriend
.4. Где бы я тогда вызвал функцию checkFriendRequest() для обновления переменной isFriend?
5. @Харикришнасентхилкумар традиционно, что-то вроде
onAppear
Ответ №1:
Представления SwiftUI автоматически запускают обновления в соответствии с состоянием их представлений. Поскольку вызовы Firebase являются асинхронными, вы не можете ожидать, что синхронный вызов функции выборки вернется с правильным результатом.
Вместо этого вам необходимо обновить опубликованное значение (в основном потоке), которое затем передаст сообщение об обновлении всем подписчикам этого значения. SwiftUI автоматически обрабатывает механизм подписки с помощью объекта состояния или объекта наблюдения и запускает новый запрос для основной части представления.
Чтобы ваш код работал с SwiftUI, настройте checkFriendRequest следующим образом:
Измените это:
if pendingFriendRequests[key] == true {
self.isFriend = 1
} else if pendingFriendRequests[key] == false {
self.isFriend = 2
}
Кому: (Потому что он запускает события пользовательского интерфейса, и весь пользовательский интерфейс должен выполняться в главном потоке)
DispatchQueue.main.async {
if pendingFriendRequests[key] == true {
self.isFriend = 1
} else if pendingFriendRequests[key] == false {
self.isFriend = 2
}
}
По вашему мнению, измените VStack на:
VStack {
if userData.isFriend == 1 {
//button for if returned 1
} else if userData.isFriend == 2 {
//button for if returned 2
} else {
}
}.onAppear() {
userData.checkFriendRequest(otherUserUID: otherUserUID)
}
Комментарии:
1. Проверьте свои
if
предложения на наличие несоответствующих скобок.2. удалены ненужные скобки.