单例模式优秀应用场景:点赞功能中的ENFeedLikeManager实现
我来帮你把这个点赞功能的单例管理类捋顺,结合你的需求给出完整的实现方案和注意细节:
单例ENFeedLikeManager完整实现
这个单例的核心作用是统一管理主页的点赞数据,同时对接推送通知的点赞事件,还要关联点赞列表的视图控制器来同步刷新UI。
1. 完整的单例代码实现
import UIKit // 先定义点赞数据模型(如果你的项目里已有,可直接复用) struct ENFeedLike: Codable { let userId: String let userName: String let avatarUrl: String? let likeTime: Date } // 点赞管理单例类 class ENFeedLikeManager: NSObject { // 全局唯一的单例实例,方便各处调用 static let sharedInstance = ENFeedLikeManager() // 弱引用关联点赞列表视图控制器,避免循环引用 weak var likeViewController: ENLikeViewController? // 存储所有点赞数据的数组,用private(set)保证外部只能读不能直接修改 private(set) var likes = [ENFeedLike]() // 私有初始化方法,禁止外部创建新实例,确保单例唯一性 private override init() { super.init() // 初始化时从本地加载之前保存的点赞数据,避免重启APP丢失 loadLikesFromLocal() } // 处理推送通知时调用的添加点赞方法 func addNewLike(_ like: ENFeedLike) { // 避免重复添加同一个用户的点赞(可根据业务需求调整判断逻辑) guard !likes.contains(where: { $0.userId == like.userId }) else { return } // 数组操作和UI相关操作必须在主线程执行,避免线程安全问题 DispatchQueue.main.async { [weak self] in self?.likes.insert(like, at: 0) // 最新点赞放在数组最前面,符合列表展示逻辑 self?.saveLikesToLocal() // 同步保存到本地 // 如果点赞列表页面正在显示,直接触发UI刷新 self?.likeViewController?.refreshLikeList() } } // 从本地加载点赞数据(用UserDefaults做轻量持久化,数据量大的话建议换CoreData/Realm) private func loadLikesFromLocal() { guard let data = UserDefaults.standard.data(forKey: "ENFeedLikes"), let savedLikes = try? JSONDecoder().decode([ENFeedLike].self, from: data) else { return } likes = savedLikes } // 将点赞数据保存到本地 private func saveLikesToLocal() { guard let data = try? JSONEncoder().encode(likes) else { return } UserDefaults.standard.set(data, forKey: "ENFeedLikes") UserDefaults.standard.synchronize() } } // 定义点赞视图控制器的协议,规范刷新UI的方法 protocol ENLikeViewController: UIViewController { func refreshLikeList() }
2. 关键细节说明
- 单例安全性:通过
private override init()禁止外部实例化,保证全局只有一个管理类实例,避免数据不一致。 - 线程安全:所有修改
likes数组和UI更新的操作都放在主线程,因为推送通知的回调大概率在后台线程执行,直接操作会有崩溃风险。 - 数据持久化:加入了UserDefaults的存储逻辑,解决APP重启后点赞数据丢失的问题;如果你的点赞数据量较大,建议改用CoreData或Realm。
- 避免重复点赞:添加了用户ID的判断逻辑,防止同一个用户的点赞被重复存入数组,你可以根据业务需求调整判断规则(比如允许同一用户多次点赞)。
- UI联动:用弱引用关联
likeViewController,新点赞到来时如果页面正在显示,直接触发刷新,比用通知中心更直接高效,还能避免不必要的监听。
3. 推送通知中的调用示例
当你收到点赞推送时,先从推送payload里解析出用户信息,创建ENFeedLike对象,再调用单例的添加方法:
// 假设从推送的userInfo中解析数据 guard let userId = userInfo["userId"] as? String, let userName = userInfo["userName"] as? String else { return } let avatarUrl = userInfo["avatarUrl"] as? String let newLike = ENFeedLike(userId: userId, userName: userName, avatarUrl: avatarUrl, likeTime: Date()) // 调用单例添加点赞 ENFeedLikeManager.sharedInstance.addNewLike(newLike)
内容的提问来源于stack exchange,提问作者Florian Ldt
相关产品推荐
相关产品推荐

