Alamofire 完成工作后如何加载视图?

Posted

技术标签:

【中文标题】Alamofire 完成工作后如何加载视图?【英文标题】:How to load view after Alamofire finished its job? 【发布时间】:2016-04-28 09:57:05 【问题描述】: 我的问题:

我正在尝试在 SubViewController 加载其视图之前通过 Alamofire 从服务器加载数据。写完代码,没能解决Alamofire的Async Feature的问题。在 Alamofire 完成工作之前,视图总是被加载到 SubViewController 中。

我的部分代码:

父视图控制器:

通过PrepareForSegue()引领SubViewController。

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 

    if segue.identifier == "CellDetailSegue" 
        if let indexPaths = self.dateCollectionView.indexPathsForSelectedItems() 
            let subViewController = segue.destinationViewController as! SubViewConroller
    

子视图控制器:

测试其viewDidLoad()中的print()是否已经加载了数据,viewWillAppear()中的dataRequest()加载数据

class SubViewController: UIViewController, UITableViewDelegate, UITableViewDataSource 

    var availablePeriods401 = [String]()
    var availablePeriods403 = [String]()
    var availablePeriods405 = [String]()

    override func viewDidLoad() 
        super.viewDidLoad() 
        self.dataRequest(self.availablePeriods401)
        self.dataRequest(self.availablePeriods403)
        self.dataRequest(self.availablePeriods405)
        print(self.availablePeriods401.count)
        print(self.availablePeriods403.count)
        print(self.availablePeriods405.count)    
    

    func dataRequest(_ target: [String]) 
      Alamofire.request(.POST, "http://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON 
            .
            .
            .
      target = Result
      
   

 
问题描述:

加载视图后,无法为 SubViewController 中的三个变量分配有效值。

三个输出的结果都是0。

但如果我在dataRequest() 中设置print(),我可以获得有效计数。

我的问题:

如何确保Alamofire 完成其工作?

我应该把 Alamofire 请求函数放在哪里? viewWillApper()? viewDidApper()?

我应该在 ParentViewController 的PrepareForSegue() 中完成请求工作吗?

请教我如何解决这个问题。

非常感谢您的指导和时间。

伊桑乔

【问题讨论】:

【参考方案1】:

您应该在 viewDidLoad 函数中调用 Alamofire 请求函数。当您收到完成块的响应(从您打印数据的位置)时,您应该reload table data

你可以像这样重新加载tableview,

 self.tableView.reloadData()

希望这会有所帮助:)

【讨论】:

首先,感谢您的回答。我有一个问题:我不确定每次拨打reloadData()时是否会涉及viewDidLoad()。我的意思是,viewDidLoad() 将在视图加载时被调用一次。也许您的意思是在viewWillAppear() 中设置reloadData() 在完成处理程序中获得响应时,方法中没有重新加载数据。不知道它在 swift 中调用了什么,但它是完成处理程序,仅在您获得响应后才会调用,因此在获得完整响应后重新加载表数据,以便相应地重新加载表视图。【参考方案2】:

我注意到的第一件事是您正在执行 3 个异步请求,而不是一个。您可以使用完成处理程序,但哪个?我认为你有两个选择。

    嵌套网络调用,以便完成一个调用开始下一个调用。这种方法的缺点是它们将按顺序运行,如果添加更多,则必须继续嵌套。如果您只进行 2 次调用,这样的方法可能没问题,但除此之外,它会变得越来越困难。 使用信号量等待所有远程调用的所有数据都加载完毕。使用完成处理程序向信号量发出信号。如果您要使用这种方法,则必须在后台线程上完成,因为使用信号量会阻塞线程,您不希望在主线程上发生这种情况。

这三个调用将同时发生。即使 AlamoFire 没有完成,函数也会返回。

    self.dataRequest(self.availablePeriods401)
    self.dataRequest(self.availablePeriods403)
    self.dataRequest(self.availablePeriods405)

无论 AlamoFire 是否完成,这些都会执行。

    print(self.availablePeriods401.count)
    print(self.availablePeriods403.count)
    print(self.availablePeriods405.count)    

使用信号量看起来像这样:

override func viewWillAppear(animated: Bool) 
    // maybe show a "Please Wait" dialog?

    loadMyData() 
        (success) in
        // hide the "Please Wait" dialog.

        // populate data on screen

    




func loadMyData(completion: MyCompletionHandler) 

    // Do this in an operation queue so that we are not 
    // blocking the main thread.

    let queue = NSOperationQueue()
    queue.addOperationWithBlock 
        let semaphore = dispatch_semaphore_create(0)
        Alamofire.request(.POST, "http://httpbin.org/get", parameters: ["foo": "bar1"]).responseJSON 
            // This block fires after the results come back

            // do something

            dispatch_semaphore_signal(semaphore);
        
        Alamofire.request(.POST, "http://httpbin.org/get", parameters: ["foo": "bar2"]).responseJSON 
            // This block fires after the results come back

            // do something

            dispatch_semaphore_signal(semaphore);
        
        Alamofire.request(.POST, "http://httpbin.org/get", parameters: ["foo": "bar3"]).responseJSON 
            // This block fires after the results come back

            // do something

            dispatch_semaphore_signal(semaphore);
        

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)

        completion(true)
    

Apple Docs - Grand Central Dispatch

How to use semaphores

我要问你的问题是,如果一些,不是所有的网络调用都失败了,你会怎么做?

【讨论】:

感谢您的回答。问题解决了。【参考方案3】:

先用false创建一个全局bool变量

 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 

     if segue.identifier == "CellDetailSegue" && boolVar 
         if let indexPaths =      self.dateCollectionView.indexPathsForSelectedItems() 
             let subViewController = segue.destinationViewController as! SubViewConroller
     
 

使用 segue 名称和 boolVar true 从 almofire 块调用 prepare segue。

【讨论】:

感谢您的回答和时间。我有一个问题:假设一种情况,我按下一个按钮或其他东西来从 ParentViewController 转换到 SubViewController,这意味着它将调用prepareForSegue()。好吧,如果boolVarfalse 当我触发此转换时,您的解决方案会起作用吗(恕我直言!!!)?视图会在 Alamofire 获取其数据之前被冻结,还是我需要在 Alamofire 获取其数据时按下按钮触发转换? 这个答案没有意义。

以上是关于Alamofire 完成工作后如何加载视图?的主要内容,如果未能解决你的问题,请参考以下文章

加载远程数据后 swift alamofire 显示视图控制器

alamofire 请求完成后更新 tableview

从 alamofire swift 的 tableview 单元格中的 url 加载图像

从后台获取调用时,Alamofire 不工作

使用 Alamofire 将文件保存到 .DocumentDirectory

如何在响应闭包中访问 Alamofire 请求参数?