completionHandler / userCompletionHandler 问题 - Swift iOS

Posted

技术标签:

【中文标题】completionHandler / userCompletionHandler 问题 - Swift iOS【英文标题】:completionHandler / userCompletionHandler problem - Swift iOS 【发布时间】:2019-04-04 00:19:18 【问题描述】:

下面有两个函数:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", for: indexPath)
    let message = self.messages[indexPath.row]

    // Set table cell values

    getUserFriendlyName(sid: message.sid!, arg: true, completion:  (success) -> Void in

        cell.detailTextLabel?.text = self.friendly_name
        cell.textLabel?.text = message.body
        cell.selectionStyle = .none
        //self.tableView.reloadData()
    )

    return cell

func getUserFriendlyName(sid: String, arg: Bool, completion: @escaping (Bool) -> ()) 

    let ACCOUNT_IDENTITY: String = "AC***redacted"
    let AUTH_TOKEN: String = "**redacted"
    let SERVICE_ID: String = "IS***redacted"

    let loginString = "\(ACCOUNT_IDENTITY):\(AUTH_TOKEN)"

    let loginData = loginString.data(using: String.Encoding.utf8)

    let base64LoginString = loginData!.base64EncodedString()

    let url = URL(string: "https://chat.twilio.com/v2/Services/IS***redacted/Users/US***redacted")

    var request = URLRequest(url: url!)
    var session = URLSession.shared
    request.httpMethod = "GET"
    request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
    request.addValue("application/json", forHTTPHeaderField: "Accept")
    //request.addValue(AUTH_TOKEN, forHTTPHeaderField: "Authorization")
    var fn: String!
    let task = session.dataTask(with: request, completionHandler:  data, response, error in
        var strData = String(data: data!, encoding: String.Encoding.utf8)
        print("Body: \(strData)")
        guard error == nil else 
            print(error!)
            return
        
        guard let data = data else 
            print("Data is empty")
            return
        

        let json = try! JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary

        //getting the json response
        print(json)
        fn = json["friendly_name"] as! String?
        self.friendly_name = fn

        completion(arg)
        //return fn
        //print(fn)
    )

    task.resume()


这是我遇到的问题...当检测到新的聊天消息时,会调用 tableView 函数。使用文本和潜文本创建一个新单元格。因为本机 Twilio 代码不允许我显示写聊天的人的友好名称,所以我必须进行 HTTP 调用,所以我调用 getUserFriendlyName()。因为 resumeTask() 是异步的,所以程序的流程是这样的:

    tableView函数进入 我调用了 getUserFriendlyNameFunction(),它会被输入 当我们到达HTTP请求时,resumeTask()被调用,然后流程返回到tableView函数,特别是友好用户名函数的调用结束并执行return Cell line,这意味着单元格已创建但包含原型数据,即文本的“标题”和描述文本的“副标题”。 然后流程返回到 HTTP 请求并被执行 在tableView函数内部调用getUserFriendlyName()后,流程直接返回到代码行。该代码将文本和详细文本值设置为 HTTP 调用返回的数据。但此时,该单元格已经存在于我的 tableView 中。所以我只剩下一个包含“文本”和“子文本”的单元格。

我尝试过的:

    在 tableView 函数的最后几行代码执行后添加 tableView.reloadData()。这没有使用来自 HTTP 调用的数据更新 tableView。事实上,它一遍遍地不断刷新tableView。

    将最后三行代码移动到与“返回单元格”行相同的位置。这也不起作用。

我开始相信我唯一的希望是completionHandler / userCompletionHandler。我已经和他们玩了很长时间,但无法得到想要的结果,那就是让第一条传入的聊天消息填充来自 HTTP 请求的数据。

谁能帮忙?

【问题讨论】:

1.从cellForRowAt 中删除异步调用。 2. 进行异步调用,然后更新表的数据(self.messages)。 3.调用tableView.reloadData(),确保你在主线程上.. 【参考方案1】:

当您收到消息时,不要直接将其添加到消息数组中,而是先调用

// this goes inside some function not cellForRowAt

let message =  // received 

getUserFriendlyName(sid: message.sid!, arg: true, completion:  (success) -> Void in 
       message....// set all needed properties
       self.messages.append(message)
       self.tableview.reloadRows(at:[IndexPath(row:messages.count - 1,section:0)],with:.none)

不要在cellForRowAt 中做任何异步工作,因为它会在每次滚动时完成,此外它不会同时显示完整数据


session.dataTask(with: request 的完成是在后台线程中,所以请考虑

DispatchQueue.main.async 
  completion(arg)


你让self.friendly_name

self.friendly_name = fn

一个 vc 属性,但它应该是每个消息对象的一个​​属性,因此不要与其他消息发送者混合

【讨论】:

好的,我明白了。我想我明白你对 Cellforrowat 的看法了……我不知道它也是异步执行的。我将重新排列我的代码,一旦我让它工作,我将发布完成的两个方法。谢谢大家!

以上是关于completionHandler / userCompletionHandler 问题 - Swift iOS的主要内容,如果未能解决你的问题,请参考以下文章

GMSGeoCoder reverseGeocodeCoordinate:completionHandler:在后台线程上

completionHandler 和 [弱按钮]

NIO2 CompletionHandler 的线程安全

我的 CompletionHandler 不会执行。为啥?

completionHandler 的响应为零

AVAudioPlayerNode scheduleFile:atTime:completionHandler: 不调用完成处理程序