Swift:如何通过布尔变量更新关注/取消关注按钮标题
问题:无法根据关注状态更新Instagram式的关注/取消关注按钮
我想要实现一个类似Instagram的关注/取消关注按钮,目前的实现代码如下:
为按钮创建了IBOutlet并通过didSet设置属性:
@IBOutlet weak var followButtonOutlet: UIButton! { didSet { if !following { followButtonOutlet.setTitle("Follow", for: .normal) followButtonOutlet.backgroundColor = Colors.indexedPrimary } else { followButtonOutlet.setTitle("Unfollow", for: .normal) followButtonOutlet.backgroundColor = Colors.indexedPrimary } } }
同时定义了following布尔变量,通过检查Firestore数据判断用户是否已关注:
func checkIfUserIsFollowing(){ guard let currentUID = Auth.auth().currentUser?.uid, let userID = user.uid else { return } COLLECTION_USERS.document(currentUID).collection("following").document(userID).getDocument { snapshot, err in if let snapshot = snapshot { if snapshot.exists == true { self.following = true } else { self.following = false } } else { print("Error retrieving document: \(err)") } } }
现在遇到的问题是:按钮无法根据用户是否在关注列表中更新标题和状态。未关注时应该显示“Follow”,已关注时显示“Unfollow”,请问正确的实现方式是什么?
解决方法
你的问题核心在于**following变量变化时没有触发按钮的更新逻辑**——当前的didSet只在followButtonOutlet被初始化或重新赋值时执行,而following改变时不会自动调用这段代码。按以下步骤修改:
- 给
following变量添加didSet观察者,变量变化时直接更新按钮状态
var following: Bool = false { didSet { updateFollowButtonState() } }
- 把按钮的UI更新逻辑抽成独立方法,方便复用和维护
private func updateFollowButtonState() { // 确保按钮已加载,避免nil报错 guard let button = followButtonOutlet else { return } if following { button.setTitle("Unfollow", for: .normal) // 可选优化:已关注时切换为浅灰边框样式,和Instagram保持一致 button.backgroundColor = .systemGray5 button.setTitleColor(.label, for: .normal) button.layer.borderWidth = 1 button.layer.borderColor = UIColor.systemGray4.cgColor } else { button.setTitle("Follow", for: .normal) button.backgroundColor = Colors.indexedPrimary button.setTitleColor(.white, for: .normal) button.layer.borderWidth = 0 } }
- 调整Outlet的
didSet,只在按钮初始化时调用一次更新方法
@IBOutlet weak var followButtonOutlet: UIButton! { didSet { updateFollowButtonState() } }
- 优化
checkIfUserIsFollowing(),确保在主线程更新UI(Firestore回调默认在后台线程)
func checkIfUserIsFollowing(){ guard let currentUID = Auth.auth().currentUser?.uid, let userID = user.uid else { return } COLLECTION_USERS.document(currentUID).collection("following").document(userID).getDocument { snapshot, err in DispatchQueue.main.async { if let snapshot = snapshot { self.following = snapshot.exists } else { print("Error retrieving document: \(err)") } } } }
- 实现按钮点击的关注/取消关注逻辑,操作完成后更新
following变量(自动触发UI刷新)
@IBAction func followButtonTapped(_ sender: UIButton) { guard let currentUID = Auth.auth().currentUser?.uid, let userID = user.uid else { return } if following { // 取消关注:同时删除当前用户following和目标用户followers集合中的记录 COLLECTION_USERS.document(currentUID).collection("following").document(userID).delete { [weak self] err in if let err = err { print("取消关注失败:\(err)") return } COLLECTION_USERS.document(userID).collection("followers").document(currentUID).delete { err in if let err = err { print("更新对方粉丝列表失败:\(err)") return } DispatchQueue.main.async { self?.following = false } } } } else { // 关注:同时添加到当前用户following和目标用户followers集合 let timestamp = Timestamp(date: Date()) let followingData = ["timestamp": timestamp] COLLECTION_USERS.document(currentUID).collection("following").document(userID).setData(followingData) { [weak self] err in if let err = err { print("关注失败:\(err)") return } let followerData = ["timestamp": timestamp] COLLECTION_USERS.document(userID).collection("followers").document(currentUID).setData(followerData) { err in if let err = err { print("更新粉丝列表失败:\(err)") return } DispatchQueue.main.async { self?.following = true } } } } }
关键说明
following的didSet是核心:每次变量变化都会自动触发按钮UI更新- 将UI逻辑抽成独立方法,避免重复代码,也方便后续调整样式
- Firestore回调在后台线程,必须切换到主线程更新UI,否则可能导致界面无响应
- 关注/取消关注时要同时维护两个集合(当前用户的
following和目标用户的followers),保证数据一致性
内容的提问来源于stack exchange,提问作者Vandal
相关产品推荐
相关产品推荐

