6

Basically I have a code for posting simple data to a server and will return a boolean value success if the post request was successful but it seems to be that the boolean value is returned before even the data is processed, am I doing something wrong?

public func postRequest(rawText: String) -> Bool {
    var success = true
    let destUrl = "http://api.getquesto.com:8080/upload/"
    var request = URLRequest(url: URL(string: destUrl)!)
    request.httpMethod = "POST"
    let postString = rawText
    request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
//    request.setValue("compute", forHTTPHeaderField: "Questo-Query")
//    request.setValue("Fuck you", forHTTPHeaderField: "quizTitle")

    request.httpBody = postString.data(using: .utf8)
    print(request.httpBody!)
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else {                                                 // check for fundamental networking error
            print("error=\(error)")
            success = false
            print(success)

            return
        }

        if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           // check for http errors
            print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(response)")
        }

        let responseString = String(data: data, encoding: .utf8)
        do {
            if let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions(rawValue: UInt(0))) as? [String: Any] {
                print("json \(json)")
            } else {
                print("can not cast data")
                success = false

            }
        } catch let error {
            print("cant parse json \(error)")
            success = false
            print(success)

        }

        print("responseString = \(responseString)")
        let dataString = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
        //print(dataString)
        //print("responseString = \(responseString)")
        constantVariables.rawQuestionData = dataString as! String
        let processedResults = dataString?.replacingOccurrences(of: "\\n", with: " ")
        print("processed results = " + (processedResults! as String))
        let newArray = processedResults!.components(separatedBy: ", \"")
        //print(newArray)

        for index in 0...(newArray.count - 1) {
            if index%2 == 0 {
                constantVariables.questions.insert(newArray[index].replacingOccurrences(of: "\"", with: "").replacingOccurrences(of: "]", with: "").replacingOccurrences(of: "[", with: ""), at: index/2)

                //        ConstantsArray.questionArray.append(newArray[index])
                //        print("question array: " + ConstantsArray.answerArray[index/2])
            }else{
                constantVariables.answers.insert(newArray[index].replacingOccurrences(of: "\"", with: "").replacingOccurrences(of: "]", with: "").replacingOccurrences(of: "[", with: ""), at: (index-1)/2)

                //        ConstantsArray.questionArray.append(newArray[index])
                print("answer array: " + constantVariables.answers[(index-1)/2])

            }
        }
    }
    task.resume()
    print(success)
    return success
    }
Ahmad F
  • 30,560
  • 17
  • 97
  • 143
Taichi Kato
  • 602
  • 9
  • 24
  • 2
    `URLSessionDataTask` is asynchronous, when you call `resume()` your code will continue and task starts in two parallel threads. If you want it to be synchronous, make an extension with code similar to this: http://stackoverflow.com/a/34308158/2122979 – Ossir Nov 27 '16 at 13:56
  • More similar questions with answers: http://stackoverflow.com/questions/40810108/swift-http-request-use-urlsession, http://stackoverflow.com/questions/40811500/ios-swift-value-of-an-integer-is-not-being-saved, http://stackoverflow.com/questions/40756123/swift-ensure-urlsession-datatask-is-completed-in-my-function-before-passing-res, http://stackoverflow.com/questions/40491502/swift-3-send-make-synchronous-http-request, ... – Martin R Nov 27 '16 at 14:14

1 Answers1

7

This is happening because the function directly returns the value of success, dataTask works asynchronously, so, the function should NOT wait until dataTask finishes the parsing to edit the value of success, i.e: return success is executed before dataTask edits the value of success.

I suggest to let the function handles a completion closure instead of direct returning of Bool.

Your function should be similar to:

public func postRequest(rawText: String, completion: @escaping (_ success: Bool) -> ()) {
    var success = true
    let destUrl = "http://api.getquesto.com:8080/upload/"
    var request = URLRequest(url: URL(string: destUrl)!)
    request.httpMethod = "POST"
    let postString = rawText
    request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
    //    request.setValue("compute", forHTTPHeaderField: "Questo-Query")
    //    request.setValue("Fuck you", forHTTPHeaderField: "quizTitle")

    request.httpBody = postString.data(using: .utf8)
    print(request.httpBody!)
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else {                                                 // check for fundamental networking error
            print("error=\(error)")
            success = false
            print(success)

            return
        }

        if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           // check for http errors
            print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(response)")
        }

        let responseString = String(data: data, encoding: .utf8)
        do {
            if let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions(rawValue: UInt(0))) as? [String: Any] {
                print("json \(json)")
            } else {
                print("can not cast data")
                success = false

            }
        } catch let error {
            print("cant parse json \(error)")
            success = false
            print(success)

        }

        print("responseString = \(responseString)")
        let dataString = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
        //print(dataString)
        //print("responseString = \(responseString)")
        constantVariables.rawQuestionData = dataString as! String
        let processedResults = dataString?.replacingOccurrences(of: "\\n", with: " ")
        print("processed results = " + (processedResults! as String))
        let newArray = processedResults!.components(separatedBy: ", \"")
        //print(newArray)

        for index in 0...(newArray.count - 1) {
            if index%2 == 0 {
                constantVariables.questions.insert(newArray[index].replacingOccurrences(of: "\"", with: "").replacingOccurrences(of: "]", with: "").replacingOccurrences(of: "[", with: ""), at: index/2)

                //        ConstantsArray.questionArray.append(newArray[index])
                //        print("question array: " + ConstantsArray.answerArray[index/2])
            }else{
                constantVariables.answers.insert(newArray[index].replacingOccurrences(of: "\"", with: "").replacingOccurrences(of: "]", with: "").replacingOccurrences(of: "[", with: ""), at: (index-1)/2)

                //        ConstantsArray.questionArray.append(newArray[index])
                print("answer array: " + constantVariables.answers[(index-1)/2])

            }
        }

        completion(success)
    }
    task.resume()
    print(success)
}

In Swift 3, you should use @escaping, for more information, you might want to check this answer.

Calling:

postRequest(rawText: "rawText", completion: { success in
    print(success)
})

Now, it should wait untill dataTask finish it's parsing, and then, the code in the completion will be called.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143