如何实现类Tinder应用中双向点赞后的用户匹配功能
实现Tinder式双向匹配逻辑方案
一、核心思路调整
你当前的问题在于跳过了「单向点赞→对方确认→双向匹配」的中间流程,直接将被点赞用户加入匹配数组。正确的逻辑应该是:
- 用户点赞后,先将对方存入已发出点赞列表,同时同步到Firebase
- 被点赞用户会在通知视图看到来自你的点赞,若对方也点赞你,则触发双向匹配
- 只有双方互相点赞后,才将对方加入最终的匹配数组
二、代码结构修改
1. 完善Person结构体(添加唯一标识)
必须给每个用户添加唯一ID,用于Firebase中的数据关联:
struct Person: Identifiable, Hashable { let id: String // 对应Firebase用户文档ID,作为唯一标识 var username: String var age: Int }
2. 更新UserManager数据与逻辑
新增待确认的点赞数组,并实现Firebase数据同步、匹配检查逻辑:
class UserManager: ObservableObject { @Published var userInfo: UserInfo? @Published var people: [Person] = [] // 所有其他用户 @Published var matches: [Person] = [] // 已匹配用户 @Published var sentLikes: [Person] = [] // 我发出的点赞(待对方确认) @Published var receivedLikes: [Person] = [] // 收到的点赞(供我确认) // Firebase用户集合引用 private let usersRef = Firestore.firestore().collection("users") // 点赞用户的核心方法 func likePerson(_ person: Person) { guard let currentUserId = userInfo?.id else { return } // 先更新本地已发出点赞列表 if !sentLikes.contains(person) { sentLikes.append(person) } // 同步到Firebase:更新当前用户的已点赞列表 usersRef.document(currentUserId).updateData([ "sent_likes": FieldValue.arrayUnion([person.id]) ]) { error in if let error = error { print("点赞同步失败:\(error.localizedDescription)") // 失败时回滚本地数据 if let index = self.sentLikes.firstIndex(of: person) { self.sentLikes.remove(at: index) } return } // 同步到对方的收到点赞列表 self.usersRef.document(person.id).updateData([ "received_likes": FieldValue.arrayUnion([currentUserId]) ]) // 检查对方是否已经点赞过我,触发双向匹配 self.checkForMutualLike(with: person) } } // 检查是否双向点赞,完成匹配 private func checkForMutualLike(with person: Person) { guard let currentUserId = userInfo?.id else { return } // 获取对方的已点赞列表,判断是否包含当前用户ID usersRef.document(person.id).getDocument { snapshot, error in if let error = error { print("获取对方点赞数据失败:\(error.localizedDescription)") return } guard let data = snapshot?.data(), let targetSentLikes = data["sent_likes"] as? [String], targetSentLikes.contains(currentUserId) else { return } // 双向点赞成功,加入匹配数组 if !self.matches.contains(person) { self.matches.append(person) } // 同步到Firebase双方的匹配列表 self.usersRef.document(currentUserId).updateData([ "matches": FieldValue.arrayUnion([person.id]) ]) self.usersRef.document(person.id).updateData([ "matches": FieldValue.arrayUnion([currentUserId]) ]) } } // 实时监听当前用户的点赞、匹配数据变化 func listenToUserUpdates() { guard let currentUserId = userInfo?.id else { return } usersRef.document(currentUserId).addSnapshotListener { snapshot, error in if let error = error { print("监听用户数据失败:\(error.localizedDescription)") return } guard let data = snapshot?.data() else { return } // 同步本地已发出点赞列表 if let sentLikeIds = data["sent_likes"] as? [String] { self.sentLikes = self.people.filter { sentLikeIds.contains($0.id) } } // 同步本地收到的点赞列表(用于通知视图展示) if let receivedLikeIds = data["received_likes"] as? [String] { self.receivedLikes = self.people.filter { receivedLikeIds.contains($0.id) } } // 同步本地匹配列表 if let matchIds = data["matches"] as? [String] { self.matches = self.people.filter { matchIds.contains($0.id) } } } } // 获取所有用户数据(过滤掉当前用户) func fetchAllUsers() { usersRef.getDocuments { documentsSnapshot, error in if let error = error { print("获取用户列表失败:\(error.localizedDescription)") return } self.people = documentsSnapshot?.documents.compactMap { snapshot in guard let id = snapshot.documentID as? String, let username = snapshot.data()["username"] as? String, let age = snapshot.data()["age"] as? Int else { return nil } return Person(id: id, username: username, age: age) } ?? [] // 排除当前用户自己 self.people = self.people.filter { $0.id != self.userInfo?.id } } } }
3. 修改HomeView的点赞触发逻辑
替换直接添加匹配的代码,调用新的点赞方法:
struct HomeView: View { @StateObject var userMng = UserManager() var body: some View { // 省略卡片展示等其他代码 CircleButtonView(type: .heart) { if let person = userMng.people.last { userMng.swipe(person, _direction: .like) userMng.likePerson(person) // 调用点赞方法,不再直接加入matches } } .onAppear { userMng.fetchAllUsers() userMng.listenToUserUpdates() // 开启实时数据监听 } } }
三、Firebase数据结构说明
每个用户文档需包含以下字段(数组类型):
sent_likes:存储当前用户点赞过的所有用户IDreceived_likes:存储给当前用户点赞的所有用户IDmatches:存储已双向匹配成功的用户ID
四、通知视图实现提示
你可以基于UserManager中的receivedLikes数组,在通知视图展示所有给自己点赞的用户,当用户在该视图点击爱心时,同样调用likePerson方法,触发双向匹配检查。
内容的提问来源于stack exchange,提问作者Thomas Kweblin
相关产品推荐
相关产品推荐

