completionHandler / userCompletionHandler问题 - Swift iOS

问题描述 投票:0回答:1

我有以下两个功能:

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()是异步的,所以程序的流程如下:

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

我尝试过的:

  1. 在tableView函数中的最后一行代码执行后添加tableView.reloadData()。这没有使用HTTP调用中的数据更新tableView。实际上,它一遍又一遍地不断刷新tableView。
  2. 将最后三行代码移动到与“返回单元格”行相同的位置。这也行不通。

我开始相信我唯一的希望就是/Handler / userCompletionHandler。我已经和他们玩了很长时间并且无法获得理想的结果,这将是第一个传入的聊天消息填充了来自HTTP请求的数据。

有人可以帮忙吗?

ios swift completionhandler
1个回答
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属性,它应该是每个消息对象的属性,以便不与其他消息发送者混合

© www.soinside.com 2019 - 2024. All rights reserved.