【问题标题】:Alamofire callback never returnsAlamofire 回调永远不会返回
【发布时间】:2018-04-13 07:19:23
【问题描述】:

我正在使用 Alamofire 库向 stackexchange api 发出 GET 请求,我想将从 JSON 获得的结果保存在一个数组中,问题是 alamofire 任务是异步的,我需要提供的数据通过它来完成我的工作,例如插入表格单元格等...我尝试使用信号量让我的程序等待调用,但调用永远不会到达信号()。为什么会发生这种情况?在异步调用终止后继续我的工作的另一种方式是什么?我对这些东西很陌生,所以我不太了解,感谢任何帮助。代码如下:

var users:[UserInfo] = []
var number:Int = 0
let dispatch:DispatchSemaphore = DispatchSemaphore(value: 0)


override func viewDidLoad() {

    tableView.delegate = self
    tableView.dataSource = self

    // GET the data from the stackexchange api

    let param: Parameters = [
        "order": "desc",
        "max" : 10,
        "sort" : "reputation",
        "site" : "stackoverflow"
    ]

    Alamofire.request("https://api.stackexchange.com/2.2/users", method: .get, parameters: param).responseJSON { (response) -> (Void) in


        if let json = response.result.value {
            // we got a result

            /* I know this is a bit ugly */
            let json1 = json as! [String:AnyObject]
            let usersInfoFromJSON = json1["items"] as! NSArray       // remember to cast it as NSDictionary


            for userInfo in usersInfoFromJSON {

                self.number = 70 // just for test

                let userDict = userInfo as! NSDictionary
                self.users.append(UserInfo(newName: userDict["display_name"] as! String,
                       newImageURL: userDict["profile_image"] as! String))
            }
        }
        self.dispatch.signal()
    }
    self.dispatch.wait()


    print(self.number) // just for test

    super.viewDidLoad()
}

【问题讨论】:

  • 你真的不想用 self.dispatch.wait() 阻塞主线程
  • 是的,你是对的,但解决方案是什么?
  • 首先,去掉 DispatchSemaphore。在 Alamofire.request 调用结束时做任何你需要做的事情。在上面的示例中,将print(self.number) 放在您当前拥有self.dispatch.signal() 的位置您可能希望从那里进行调用以更新 UI、停止微调器等。
  • 是的,可以,但我还有其他功能,例如 TableViewDelegate 所需的功能,需要 alamofire 调用提供的数据
  • 同样的原则也适用,从闭包中调用这些函数。表视图委托只需要立即处理没有数据。一旦你有了数据,你可以调用 tableview.reloadData() 来显示它。

标签: ios swift http networking


【解决方案1】:

首先,摆脱 DispatchSemaphore。您使用它的方式将阻塞主线程。非常糟糕的主意。

这可能就像从闭包中调用 tableView.reloadData() 一样简单。我还建议将数据加载到一个单独的函数中,以防在某些时候您想从源刷新数据。

var users:[UserInfo] = []
var number:Int = 0

override func viewDidLoad() {
    tableView.delegate = self
    tableView.dataSource = self
    loadData()

    super.viewDidLoad()
}

func loadData() {
    // GET the data from the stackexchange api
    let param: Parameters = [
        "order": "desc",
        "max" : 10,
        "sort" : "reputation",
        "site" : "stackoverflow"
    ]

    Alamofire.request("https://api.stackexchange.com/2.2/users", method: .get, parameters: param).responseJSON { (response) -> (Void) in
        if let json = response.result.value {
            // we got a result

            /* I know this is a bit ugly */
            let json1 = json as! [String:AnyObject]
            let usersInfoFromJSON = json1["items"] as! NSArray       // remember to cast it as NSDictionary

            for userInfo in usersInfoFromJSON {
                self.number = 70 // just for test

                let userDict = userInfo as! NSDictionary
                self.users.append(UserInfo(newName: userDict["display_name"] as! String,
                       newImageURL: userDict["profile_image"] as! String))
            }
        }

        self.tableView.reloadData()
        print(self.number) // just for test
    }
}

如果你想变得聪明一点,你甚至可以将 reloadData() 移动到 usersdidSet 闭包中。当然,如果您这样做,请从 Alamofire 闭包中删除 reloadData() 调用。

var users:[UserInfo] = [] {
    didSet {
        tableView.reloadData()
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-06
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 2020-11-18
    • 2019-11-15
    相关资源
    最近更新 更多