如何从NotificationsEnum类型数组中移除指定userId的通知
问题描述
我的ProfileViewModel里有一个NotificationsEnum类型的通知数组,用来根据后端推送的不同通知类型(比如点赞、评论)展示对应的SwiftUI视图。现在需要移除数组中所有userId匹配指定值的通知,但userId属性没法直接从NotificationsEnum访问。
通知结构打印示例:
[ App.NotificationsEnum.like ( App.LikeNotification(id: "62ed8df9fd9df47c", type: "like", userId: "634k32816fjh35sd35182d3", ) ) ]
相关代码如下:
VIEW MODEL 原代码
class ProfileViewModel: ObservableObject { @Published var notifications: [NotificationsEnum] = [] var subscriptions = Set<AnyCancellable>() static let removeNotifications = PassthroughSubject<String, Never>() init() { Self.removeNotifications.sink { [weak self] userId in guard let self = self else { return } // 需要实现类似下面的逻辑... // self.notifications.removeAll(where: {$0.userId == userId}) }.store(in: &subscriptions) } }
NOTIFICATION ENUM TYPE 原代码
enum NotificationsEnum: Decodable, Identifiable { var id: String { switch self { case .like(let like): return like.id case .comment(let comment): return comment.id } } case like(LikeNotification) case comment(CommentNotification) private enum CodingKeys: String, CodingKey { case type } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let type = try container.decode(String.self, forKey: .type) switch type { case "like": self = try .like(LikeNotification(from: decoder)) case "comment": self = try .comment(CommentNotification(from: decoder)) default: throw DecodingError.wrongJSON } } }
LIKE & COMMENT NOTIFICATION MODELS 原代码
struct CommentNotification: Codable, Identifiable { let id: String let type: String let userId: String let comment: String } struct LikeNotification: Codable, Identifiable { let id: String let type: String let userId: String }
解决方案
这里提供两种可行的实现方式,按需选择:
方案一:给Enum添加统一的userId计算属性(推荐)
给NotificationsEnum新增一个计算属性,统一返回不同case下的userId,后续所有需要获取用户ID的场景都能复用:
修改后的NotificationsEnum代码:
enum NotificationsEnum: Decodable, Identifiable { var id: String { switch self { case .like(let like): return like.id case .comment(let comment): return comment.id } } // 新增:统一获取userId的计算属性 var userId: String { switch self { case .like(let like): return like.userId case .comment(let comment): return comment.userId } } case like(LikeNotification) case comment(CommentNotification) private enum CodingKeys: String, CodingKey { case type } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let type = try container.decode(String.self, forKey: .type) switch type { case "like": self = try .like(LikeNotification(from: decoder)) case "comment": self = try .comment(CommentNotification(from: decoder)) default: throw DecodingError.wrongJSON } } }
然后在ProfileViewModel中直接使用该属性完成过滤:
class ProfileViewModel: ObservableObject { @Published var notifications: [NotificationsEnum] = [] var subscriptions = Set<AnyCancellable>() static let removeNotifications = PassthroughSubject<String, Never>() init() { Self.removeNotifications.sink { [weak self] userId in guard let self = self else { return } // 直接用新增的userId属性过滤 self.notifications.removeAll(where: { $0.userId == userId }) }.store(in: &subscriptions) } }
方案二:直接在过滤闭包中判断Enum case(无需修改Enum)
如果不想改动Enum的结构,可以在removeAll(where:)的闭包内通过switch逐个判断case:
修改后的ProfileViewModel代码:
class ProfileViewModel: ObservableObject { @Published var notifications: [NotificationsEnum] = [] var subscriptions = Set<AnyCancellable>() static let removeNotifications = PassthroughSubject<String, Never>() init() { Self.removeNotifications.sink { [weak self] userId in guard let self = self else { return } self.notifications.removeAll { notification in switch notification { case .like(let like): return like.userId == userId case .comment(let comment): return comment.userId == userId } } }.store(in: &subscriptions) } }
方案对比
- 方案一:代码更简洁,复用性强,适合长期维护的场景。
- 方案二:无需修改原有Enum结构,但代码冗余,仅适合临时需求。
内容的提问来源于stack exchange,提问作者kissues
相关产品推荐
相关产品推荐

