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

如何分离关注点:拆分PostManager的API调用与Post更新逻辑

问题描述

我有一个PostManager类作为单一数据源存储Post列表,代码如下:

class PostManager: ObservableObject {
    @Published var posts = [Post]()

    func updatePostMessage(postId: Int, message: String) {
        // 调用API并接收新的Post对象

        if let newPost = data.data?.post {
            self.updateMessage(for: newPost)
        }
    }

    func updateMessage(for newPost: Post) {
        if let postIndex = posts.firstIndex(where: {$0.id == newPost.id}) {
            posts[postIndex].message = newPost.message
        }
    }
}

Post结构体定义:

struct Post: Codable, Identifiable {
    var id: Int
    var title: String
    var message: String
    var createdAt: String?
    var updatedAt: String?
    // 其他更多属性...
   
    enum CodingKeys: String, CodingKey {
        case id = "id"
        case title = "title"
        case message = "message"
        case createdAt = "created_at"
        case updatedAt = "updated_at"
    }
}

现在需要在PostManager中新增数十个API调用函数,以及数十个类似updateMessage的Post属性更新函数。要求将API调用函数保留在PostManager中,把Post更新函数迁移到另一个类,同时保证@Published var posts能正常触发更新。

解决方案

1. 新建Post更新类

创建PostUpdater类,专门处理所有Post属性的更新逻辑,通过弱引用持有PostManager,避免循环引用的同时可以直接操作其posts数组:

class PostUpdater {
    private weak var postManager: PostManager?
    
    init(postManager: PostManager) {
        self.postManager = postManager
    }
    
    // 迁移原有的message更新逻辑
    func updateMessage(for newPost: Post) {
        guard let posts = postManager?.posts else { return }
        if let postIndex = posts.firstIndex(where: {$0.id == newPost.id}) {
            postManager?.posts[postIndex].message = newPost.message
        }
    }
    
    // 新增title更新方法
    func updateTitle(for newPost: Post) {
        guard let posts = postManager?.posts else { return }
        if let postIndex = posts.firstIndex(where: {$0.id == newPost.id}) {
            postManager?.posts[postIndex].title = newPost.title
        }
    }
    
    // 其他属性更新方法以此类推...
}

2. 改造PostManager集成更新类

在PostManager中初始化PostUpdater,API调用函数直接调用更新类的方法即可:

class PostManager: ObservableObject {
    @Published var posts = [Post]()
    private let postUpdater: PostUpdater
    
    init() {
        self.postUpdater = PostUpdater(postManager: self)
    }

    func updatePostMessage(postId: Int, message: String) {
        // 调用API获取新Post对象
        if let newPost = data.data?.post {
            postUpdater.updateMessage(for: newPost)
        }
    }
    
    // 新增的title更新API调用函数
    func updatePostTitle(postId: Int, title: String) {
        // 调用API获取新Post对象
        if let newPost = data.data?.post {
            postUpdater.updateTitle(for: newPost)
        }
    }
    
    // 更多API调用方法...
}

3. 优化:通用更新方法减少重复代码

如果每个更新逻辑都是替换单个属性,或者同步整个Post对象,可以写通用方法避免重复代码:

class PostUpdater {
    private weak var postManager: PostManager?
    
    init(postManager: PostManager) {
        self.postManager = postManager
    }
    
    // 通用属性更新方法,通过KeyPath指定要更新的属性
    func updatePost<Value>(withId postId: Int, keyPath: WritableKeyPath<Post, Value>, value: Value) {
        guard let posts = postManager?.posts else { return }
        if let postIndex = posts.firstIndex(where: {$0.id == postId}) {
            postManager?.posts[postIndex][keyPath: keyPath] = value
        }
    }
    
    // 同步整个Post对象的通用方法
    func syncPost(with newPost: Post) {
        guard let posts = postManager?.posts else { return }
        if let postIndex = posts.firstIndex(where: {$0.id == newPost.id}) {
            postManager?.posts[postIndex] = newPost
        }
    }
}

对应的PostManager调用可以简化:

func updatePostMessage(postId: Int, message: String) {
    if let newPost = data.data?.post {
        // 方式1:更新单个属性
        postUpdater.updatePost(withId: newPost.id, keyPath: \.message, value: newPost.message)
        // 方式2:直接同步整个Post对象
        postUpdater.syncPost(with: newPost)
    }
}

原理说明

PostManager的posts被@Published修饰,只要直接修改数组中的元素(或替换数组元素),就会触发ObservableObject的变更通知,保证UI正常更新。PostUpdater通过弱引用持有PostManager,既可以操作数据源,又不会引发循环引用问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 19:34:56