从当前 ViewController 或 parent ViewController 进行网络呼叫?

do network call from current ViewController or parent ViewController?

我正在编写一个在所有其他屏幕中都包含网络调用的应用程序。调用的结果将是特定屏幕的数据源。

问题是,我应该在 parent viewController 中进行网络调用并在推送当前 viewController 之前注入数据还是推送 currentViewController 并在 viewDidLoad()/ 上进行网络调用viewWillAppear()?

这两种方法对我来说都很有意义。

实际上,您向网络发出请求应该没有什么区别。您正在请求一些您必须等待并呈现的数据。您的问题是您应该在哪里等待接收数据。

正如@Scriptable 已经提到的,您可以执行两者中的任何一个。使用哪个取决于您希望拥有什么样的用户体验。这因情况而异,但一般来说,当我们创建资源时,我们通常会在当前屏幕上等待它,而当我们正在阅读资源时,我们会在下一个屏幕上等待它:

  1. 例如,如果您在输入新用户名和密码后创建新用户(注册),则会出现一个指示器,一旦请求完成,您将导航到下一个屏幕 "enter your personal data" 或您将收到类似 "User already exists".
  2. 的消息
  3. 然后当您按下 "My friends" 时,您将首先导航到列表,您将在其中看到 activity 指示符。然后会出现列表,或者通常是 "We could not load your data, try again."
  4. 这样的屏幕

还有其他事情需要考虑,因为对于第二种情况,您可以添加更多功能,例如数据缓存。例如,许多消息传递应用程序会将您的聊天记录保存在本地,一旦您按下某个聊天线程,您将直接导航到查看缓存的内容,并且在加载和显示一些新消息后您可能会看到。

因此,如果我们回到您应该 "call" 请求的位置,请使用所有这些,看来您最好在显示新控制器之前或同时完成。同时,我的意思是称它为先前视图控制器上的负载,但在接收新数据之前加载新视图控制器。

如何最好地做到这一点是拥有数据模型。考虑这样的事情:

class UsersModel {
    private(set) var users: [User]?
}

对于用户,我们只需要一个列表,所以我所做的只是包装一个数组。因此,在您的情况下,我们应该可以选择加载这些用户:

extension UsersModel {
    func fetchUsers() {
        User.fetchAll { users, error in
            self.users = users
            self.error = error // A new property needed
        }
    }
}

现在添加了一种加载用户并将其分配给内部 属性 的方法。这足以满足我们在第一个视图控制器中的需求:

func goToUsers() {
    let controller = UserListViewController()
    let model = UserModel()
    controller.model = model
    model.fetchUsers()
    navigationController.push(controller...
}

现在我们需要的是在第二个视图控制器中建立通信。显然我们需要在 viewDidLoad 上刷新,否则甚至会出现 on 视图。但我们还需要一些委托(或其他类型的连接),以便我们的视图控制器收到所做更改的通知:

func viewDidLoad() {
    super.viewDidLoad()

    self.refreshList()
    self.model.delegate = self
}

在刷新中我们现在应该拥有所有需要的数据:

func refreshList() {
    guard let model = model else {
        // TODO: no model? This looks like a developer bug
        return      
    }

    if let users = model.users {
        self.users = users
        tableView?.reloadData()
        if users.count.isEmpty {
             if let error = model.error {
                 // TODO: show error screen
             } else {
                 // TODO: show no data screen
             }
        }
    } else {
        // TODO: show loading indicator screen
    }

}

现在这里需要做的就是用委托完成模型:

extension UsersModel {
    func fetchUsers() {
        User.fetchAll { users, error in
            self.users = users
            self.error = error // A new property needed
            self.delegate?.usersModel(self, didUpdateUsers: self.users)
        }
    }
}

视图控制器简单地实现了:

func usersModel(_ sender: UserModel, didUpdateUsers users: [User]?) {
    refreshList()
}

现在我希望您能想象这样一个系统的美妙之处,例如您的模型可以首先从某个本地缓存或数据库异步加载用户并调用委托,然后将请求调用到服务器并再次调用委托,同时您的视图控制器会在任何情况下显示适当的数据。