-1

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

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

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

4

1 回答 1

1

您向网络发出请求的位置实际上应该没有区别。您正在请求一些数据,您将不得不等待并呈现它。您的问题是您应该在哪里等待接收数据。

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

  1. 例如,如果您在输入新用户名和密码后创建新用户(注册),则会出现一个指示符,一旦请求完成,您将导航到下一个屏幕“输入您的个人数据”,或者您将收到一个像“用户已经存在”这样的消息。
  2. 例如,当您按下“我的朋友”时,您将首先导航到列表,您将在其中看到活动指示器。然后出现列表或通常出现一些屏幕,例如“我们无法加载您的数据,再试一次”。

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

因此,如果我们回到您应该“调用”请求的位置,那么使用所有这些似乎您最好在显示新控制器之前或同时这样做。同时,我的意思是将其称为前一个视图控制器上的负载,但在收到新数据之前加载新的视图控制器。

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

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才会出现视图。但是我们还需要一些委托(或其他类型的连接),以便我们的视图控制器收到更改的通知:

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()
}

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

于 2018-03-13T12:35:43.050 回答