【问题标题】:How to load view after Alamofire finished its job?Alamofire 完成工作后如何加载视图?
【发布时间】: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() 中完成请求工作吗?


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

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

伊桑乔

【问题讨论】:

    标签: ios swift alamofire


    【解决方案1】:

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

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

     self.tableView.reloadData()
    

    希望这会有所帮助:)

    【讨论】:

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

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

    1. 嵌套网络调用,以便完成一个调用开始下一个调用。这种方法的缺点是它们将按顺序运行,如果添加更多,则必须继续嵌套。如果您只进行 2 次调用,这样的方法可能没问题,但除此之外,它会变得越来越困难。
    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 获取其数据时按下按钮触发转换?
    • 这个答案没有意义。
    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-13
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多