You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现类Tinder应用中双向点赞后的用户匹配功能

实现Tinder式双向匹配逻辑方案

一、核心思路调整

你当前的问题在于跳过了「单向点赞→对方确认→双向匹配」的中间流程,直接将被点赞用户加入匹配数组。正确的逻辑应该是:

  1. 用户点赞后,先将对方存入已发出点赞列表,同时同步到Firebase
  2. 被点赞用户会在通知视图看到来自你的点赞,若对方也点赞你,则触发双向匹配
  3. 只有双方互相点赞后,才将对方加入最终的匹配数组

二、代码结构修改

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:存储当前用户点赞过的所有用户ID
  • received_likes:存储给当前用户点赞的所有用户ID
  • matches:存储已双向匹配成功的用户ID

四、通知视图实现提示

你可以基于UserManager中的receivedLikes数组,在通知视图展示所有给自己点赞的用户,当用户在该视图点击爱心时,同样调用likePerson方法,触发双向匹配检查。

内容的提问来源于stack exchange,提问作者Thomas Kweblin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 15:40:51