get the value of variable outside of completion block from closure in swift 4

I have a project written in swift 4. It produces nil when I try to access the value inside of the closure. Here is my code:

import UIKit
import SwiftyJSON

class TchatViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    var coach_ID: String!

    var responseArr = [JSON]()
    var responseInfo = [JSON]()

    var userIDS: String?
    var typeUsers: String?
    var chatID: String?
    var appdict: NSDictionary?

    @IBOutlet weak var tblMessage: UITableView!
    @IBOutlet weak var txtMsgs: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        let userInfo = DataManager.sharedInstance.loadUser()
        getAvisList(user: userInfo!)

        tblMessage.delegate = self
        tblMessage.dataSource = self

        print("CoachIDS",coach_ID!)
    }

    func getAvisList(user: User) {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let userId = user.id
        print("chatuserId",userId!)
        self.userIDS = userId
        let userType = Int(user.type!)
        print("chatusertype",userType!)

        // var url: String = ""

        self.typeUsers = user.type!

        let todosEndpoint: String = "http://testchat.com/api/chats/createChatroomMobile"

        let newTodo = ["user_type":userType!, "user_id":userId!,"coach_id":coach_ID!] as [String : Any]

        let loader = appDelegate.showLoading()
        WebServices.sharedInstance.post(toURL: todosEndpoint, withParams: newTodo, successHandler: { (jsonData) in
            print("chatroom data: \(jsonData)")
            // self.responseArr  = jsonData.arrayValue
            let responseInfo = jsonData.dictionaryValue
            let appdict = (responseInfo as Any as! NSDictionary).value(forKey: "chatroomID")!

            print("Chatroom==",appdict) // the value gets printed here.

            let strinDuration:NSString = NSString(format:"http://testchat.com/api/chats/room/id/%@",appdict as! CVarArg)  as String as String as NSString

            print("strinDuration ==",strinDuration)

            WebServices.sharedInstance.get(toURL: strinDuration as String, successHandler: { (jsonData) in
                print("ChatHistroy: \(jsonData)")

                self.responseArr  = jsonData.arrayValue
                self.responseArr = self.responseArr.reversed()
                self.tblMessage.reloadData()
                // I am getting this data for the table view.
            }) { (error) in
                print(error)
            }

            self.appDelegate.dismissLoading(loader)
        }) { (error) in
            print(error)
            self.appDelegate.dismissLoading(loader)
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // return self.avisList.count
        return self.responseArr.count
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 200.0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: TChatCell = tableView.dequeueReusableCell(withIdentifier: "tchatcell") as! TChatCell

        let index = self.responseArr.count - indexPath.row - 1
        cell.descriptionMsg.text = self.responseArr[index]["message"].stringValue

        return cell
    }

    //Till here, it works fine. But below from here, the value gets nil.

    @IBAction func sendMessage(_ sender: Any) {
        let todosEndpoint: String = "http://testchat5479.ilovemydietcoach.com/api/chats/addMessage"

        print("self.userIDS",self.userIDS!) //It gives the value.
        print("self.typeUsers",self.typeUsers!) //It gives the value.
        print("self.chatID===", appdict)// The value of appdict is nil here.
    }
}

/// I have written the codes for webservices too for post and get methods.

class WebServices: NSObject {

static let sharedInstance = WebServices()

func post(toURL urlString:String, withParams postParams:Parameters, successHandler: @escaping (( _ jsonData:JSON) -> Void), failureHandler: @escaping((_ error:Error) -> Void)) {
    let url = URL(string: urlString)!

    let headers = ["Accept":"application/json", "Content-Type":"application/json"]

    Alamofire.request(url, method: .post, parameters: postParams, encoding: JSONEncoding.default, headers: headers).responseJSON { (response) -> Void in

        switch response.result {
        case .success(let value):
            let tempInfo = JSON(value)
            successHandler(tempInfo)
        case .failure(let error):
            failureHandler(error)
        }
    }

}
   func get(toURL urlString:String, successHandler: @escaping (( _ jsonData:JSON) -> Void), failureHandler: @escaping((_ error:Error) -> Void)) {
    let url = URL(string: urlString)!

    let headers = ["Accept":"application/json", "Content-Type":"application/json"]

    Alamofire.request(url, method: .get, encoding: JSONEncoding.default, headers: headers).responseJSON { (response) in
        switch response.result {
        case .success(let value):
            let tempInfo = JSON(value)
            successHandler(tempInfo)
        case .failure(let error):
            failureHandler(error)
        }
    }

}

}

The appdict has some value inside of closure before but it is nil here. And I have to use the value of appdict here. How can I solve it in swift 4?

1 answer

  • answered 2018-10-09 16:36 ODYN-Kon

    When you assign to appdict in closure, you're shadowing your member variable by using let:

    let appdict = (responseInfo as Any as! NSDictionary).value(forKey: "chatroomID")!
    

    With let, you're creating a local variable that shadows the member appdict. If you remove let, you'll be assigning to member variable.