从当前的ViewController或父ViewController进行网络调用?

时间:2018-03-13 10:42:24

标签: ios swift networking urlsession ios-lifecycle

我正在编写一个包含每个其他屏幕中的网络呼叫的应用。调用的结果将是特定屏幕的dataSource。

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

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

1 个答案:

答案 0 :(得分:1)

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

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

  1. 例如,如果您在输入新用户名和密码后创建新用户(注册),则会显示一个指示符,一旦请求完成,您将导航到下一个屏幕"输入您的个人数据& #34;或者你会收到一条消息,例如"用户已经存在"。
  2. 然后当你按下"我的朋友"您将首先导航到列表,您将看到活动指示器。然后列表显示或通常是某些屏幕,例如"我们无法加载您的数据,请重试。"
  3. 还有其他事情需要考虑,因为对于第二种情况,您可以添加更多功能,如数据缓存。例如,许多消息传递应用程序将在本地保存您的聊天记录,一旦您按下某个聊天线程,您将直接导航以查看缓存的内容,并且您可能会在加载并显示一些新消息后看到。

    如果我们回到你应该回到的地方,那就使用所有这些"打电话给"在您显示新控制器之前或同时,您似乎最好这样做。同时我的意思是将其称为前一个视图控制器上的负载,但在收到新数据之前加载新的视图控制器。

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

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

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