UIView 在使用 SwiftyJSON 和 Alamofire 从 API 返回数据之前渲染

UIView got rendered before data from API returned using SwiftyJSON and Alamofire

我想使用 API 获取数据 request.The 数据是使用 SwiftyJson 和 Alamofire 获取的。问题是数据已获取,但在值 fetched.How 之前加载了视图我可以解决问题吗?我的代码如下:

func fetchData(){
    Alamofire.request(favUrl, method: .get, parameters: [:]).responseJSON {
        response in
        if response.result.isSuccess{

            let dataFetched : JSON = JSON(response.result.value!)
            //print(dataFetched)
            let titleDisp = dataFetched["title"].arrayObject as? [String]
            //print(titleDisp)
            self.trackList = dataFetched["track_id"].arrayObject as? [String]

            print(self.trackList)

        }else{
            print("Error \(String(describing: response.result.error))")

        }
    }
}


override func viewDidLoad() {
    super.viewDidLoad()
    fetchData()
 }

Alamofire 方法 运行s 是异步的。不在 UIThread.Then 中,您必须在方法 运行 完成后重新加载这些视图。

作为示例 - 表格视图

func fetchData(){
    Alamofire.request(favUrl, method: .get, parameters: [:]).responseJSON {
        response in
        if response.result.isSuccess{

            let dataFetched : JSON = JSON(response.result.value!)
            //print(dataFetched)
            let titleDisp = dataFetched["title"].arrayObject as? [String]
            //print(titleDisp)
            self.trackList = dataFetched["track_id"].arrayObject as? [String]

            print(self.trackList)

            // In here you have to reload, set your uiviews or all calculation

            tableview.reloadData()

        }else{
            print("Error \(String(describing: response.result.error))")

        }
    }
}

了解应用 运行 多线程很重要。主线程,也称为 UI 线程,执行应用程序可见部分的操作,包括显示视图、对按钮做出反应等。

您不能阻塞主线程。

当您调用外部资源(例如 API 调用或加载外部图像)时,它们会在单独的线程上执行。该线程独立于主线程。两个线程都不等待另一个。在加载数据时,应用程序仍会对按钮做出反应。您要求的是在加载数据之前阻止显示视图。您可以这样做,但您必须了解这可能需要一些时间,具体取决于您的网络连接。您可以采用两种方法。

  1. 转换到显示数据的视图,但在屏幕上放置一个 "Loading" 元素,直到数据加载,然后删除 "Loading" 元素,然后重新显示包含数据的视图.

  2. 在显示视图之前加载数据。让前一个视图加载数据,然后转到必须显示数据的视图。

您还必须决定此数据是加载一次还是每次显示视图时都加载。通过将调用置于 viewDidLoad 中,API 调用只会发生一次,直到应用程序重新启动。如果您希望每次显示屏幕时都加载数据,请将调用放在 viewWillAppear 中。

// Approach #1
func fetchData(){

    self.showSpinner() 

    Alamofire.request(favUrl, method: .get, parameters: [:]).responseJSON {
        response in
        self.hideSpinner() 
        if response.result.isSuccess {

            let dataFetched : JSON = JSON(response.result.value!)
            //print(dataFetched)
            let titleDisp = dataFetched["title"].arrayObject as? [String]
            //print(titleDisp)
            self.trackList = dataFetched["track_id"].arrayObject as? [String]

            print(self.trackList)

            // Actually update the relevant screen elements here.

        } else {
            print("Error \(String(describing: response.result.error))")
        }
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    //fetchData()
}

override func viewWillAppear() {
    super.viewWillAppear()
    fetchData()
}

func showSpinner() {
    // IMPLEMENT ME
}
func hideSpinner() {
    // IMPLEMENT ME
}