如何等待下载任务在swift 3中完成

时间:2017-08-29 10:30:33

标签: swift asynchronous semaphore nsurlsession

我正在尝试构建用户注册表单,该表单应检查用户是否已存在。所以我发送一个php请求到我的mysql服务器。如果返回值为空,则用户尚不存在。

Unfortunatley我真的很难等待这个检查完成。我尝试了几种解决方案,我发现googleing但没有一个有效。我当前的代码使用信号量并且会因为"致命错误而崩溃:在解开一个Optional值"时意外地发现nil,所以信号量不会等到任务完成之后就像我期望的那样。

任何提示,将不胜感激。谢谢你们。

private func isUniqueEmail(email: String) -> Bool {
    var result: Bool?
    let semaphore = DispatchSemaphore(value: 1)
    let requestURL = URL(string: "http://localhost/firstpostget/functions/get.php")
    var request = URLRequest(url: requestURL!)
    request.httpMethod = "POST"
    let postParameters = "email=" + email
    request.httpBody = postParameters.data(using: .utf8)
    let configuration = URLSessionConfiguration.default
    let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
    let task = session.dataTask(with: request) {(data, response, error) in
        var myJson: AnyObject
        do{
            myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
            if myJson.count == 0{
                result = true
                semaphore.signal()
            } else{
                result = false
                semaphore.signal()
            }
        } catch{
            //TODO
            print(error)
        }
    }
    task.resume()

    semaphore.wait(timeout: .distantFuture)
    return result!
}

5 个答案:

答案 0 :(得分:1)

你的任务是异步的,你强行解开零值,这就是它崩溃的原因。

您必须将您的函数实现更改为异步,例如使用闭包:

private func isUniqueEmail(email: String, completion: ((Bool) -> (Void))?) {
    let requestURL = URL(string: "http://localhost/firstpostget/functions/get.php")
    var request = URLRequest(url: requestURL!)
    request.httpMethod = "POST"
    let postParameters = "email=" + email
    request.httpBody = postParameters.data(using: .utf8)
    let configuration = URLSessionConfiguration.default
    let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
    let task = session.dataTask(with: request) {(data, response, error) in
        var myJson: AnyObject
        do{
            myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
            if myJson.count == 0 {
                completion?(true)
            } else{
                completion?(false)
            }
        } catch{
            //TODO
            print(error)
        }
    }
    task.resume()
}

现在您可以这样使用此功能:

isUniqueEmail(email: "aaa@bbbb.com") { result in
    if result {
        print("email unique")
    } else {
        print("email not unique")
    }
}

答案 1 :(得分:1)

我认为您应该重新考虑用于从请求中获取数据的模式,您应该考虑使用自定义处理程序/回调方法,并将其与您尝试检查的电子邮件一起传递。请参阅下面的示例:

hot.addHook('afterGetColHeader', RemoveUnWantedHeader); 

function RemoveUnWantedHeader(col, th) {
if (th.textContent == "A" || th.textContent == "B" || th.textContent == "C" 
   || th.textContent == "D" || th.textContent == "E"
   || th.textContent == "F" || th.textContent == "G" || th.textContent == 
"H" 
   || th.textContent == "I" || th.textContent == "J"
   || th.textContent == "K" || th.textContent == "L" || th.textContent == 
"M" 
   || th.textContent == "N" || th.textContent == "O"
   || th.textContent == "P" || th.textContent == "Q" || th.textContent == 
"R" 
   || th.textContent == "S" || th.textContent == "T"
   || th.textContent == "U" || th.textContent == "V" || th.textContent == 
"W" 
   || th.textContent == "X" || th.textContent == "Y" || th.textContent == 
 "Z"
   || th.textContent == "AQ" || th.textContent == "AR" || th.textContent == 
"AS"
   || th.textContent == "AT" || th.textContent == "AU" || th.textContent == 
"AV" || th.textContent == "AW") {
    th.style.display = 'none';
 }
}

生成

private func isUniqueEmail(email: String, handler: ((_ result: Bool) -> Void)?) -> Void {
    let requestURL = URL(string: "http://localhost/firstpostget/functions/get.php")
    var request = URLRequest(url: requestURL!)
    request.httpMethod = "POST"
    let postParameters = "email=" + email
    request.httpBody = postParameters.data(using: .utf8)
    let configuration = URLSessionConfiguration.default
    let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
    let task = session.dataTask(with: request) {(data, response, error) in
        var myJson: AnyObject
        var result: Bool = false
        do{
            myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject

            if myJson.count == 0 {
                result = true
            }

            guard handler != nil else {
                return
            }

            handler!(result)

        } catch{
            //TODO
            print(error)
        }
    }
    task.resume()
}

如果你真的想沿着“等待”路线走下去,那就去isUniqueEmail(email: "test@test.com", handler: { result in print(result) // true || false })

https://developer.apple.com/documentation/dispatch/dispatchgroup

答案 2 :(得分:0)

您可以使用URlSession,如:

     func isUniqueEmail(email: String,completion: @escaping (Bool) -> ()) {

    var request = URLRequest(url: URL(string: "http://localhost/firstpostget/functions/get.php")!)
    request.httpMethod = "POST"
    let postString = "email=\(email)"
    request.httpBody = postString.data(using: .utf8)


    // loading to wait request
    UIApplication.shared.isNetworkActivityIndicatorVisible = true


    let task = URLSession.shared.dataTask(with: request) { data, response, error in

        // we get request request

        UIApplication.shared.isNetworkActivityIndicatorVisible = false

        guard let data = data, error == nil else {                                                 // check for fundamental networking error
            print("error=\(String(describing: error))")
            completion(false)

            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 = \(String(describing: response))")
           completion(false)
        }else{

            completion(true)

        }


        let responseString = String(data: data, encoding: .utf8)
        print("responseString = \(String(describing: responseString))")
    }



    task.resume()
}

并在代码中使用

self.isUniqueEmail(email: "your Email") { (isExit) in

    if isExit {


    }else{


    }
}

答案 3 :(得分:0)

尝试使用:

<强> ApihelperClass

static let sharedInstance = ApihelperClass()

typealias CompletionHandler = (_ success:Bool, _ error:Bool, _ result:NSDictionary) -> Void
typealias ErrorHandler =  (_ success: Bool, _ error:Bool) -> Void

    func callPostRequest(_ urlPath: String, params:[String: AnyObject], completionHandler: @escaping CompletionHandler, errorHandler:@escaping ErrorHandler ){

        print("urlPath:==> \(urlPath) ")
        let session = Foundation.URLSession.shared
        let url = URL(string: urlPath)
        var request = URLRequest(url : url!)
        request.httpMethod = "POST"

        do {

            let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)

            request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
            request.httpBody = jsonData

            session.dataTask(with: request, completionHandler: { data, response, error in
                OperationQueue.main.addOperation {

                    guard error == nil && data != nil else {                                                          // check for fundamental networking error
                        print("error=\(error)")
                        errorHandler(false, true)
                        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: String.Encoding.utf8)
                    print("responseString = \(responseString!)")

                    if let responsedata = responseString!.data(using: String.Encoding.utf8)! as? Data{

                        do {

                            let jsonResult:NSDictionary = try JSONSerialization.jsonObject(with: responsedata, options: []) as! NSDictionary
                            print("Get The Result \(jsonResult)")
//parse your jsonResult as per your requirements 
                            if error != nil {
                                print("error=\(error)")

                                completionHandler(false, true, jsonResult)//
                            }


                            if let str = jsonResult["success"] as? NSNull {
                                print("error=\(str)")

                                completionHandler(false, true, jsonResult)

                            }
                            else {
                                let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
                                //                                    print("Response string : \(responseString)")
                                completionHandler(true, false, jsonResult)
                            }



                        } catch let error as NSError {
                            print(error.localizedDescription)
                        }
                    }
                }
            }) .resume()
        }catch {
                print("Error ->Catch")
        }
    }

添加到您的viewcontroller

func isUniqueEmail(email: String){
    ApihelperClass.sharedInstance.callPostRequest("http://localhost/firstpostget/functions/get.php", params: ["email":email as AnyObject], completionHandler: { (success, error, result) in
        //success 200
    }) { (success, error) in
        //error
    }
}

答案 4 :(得分:0)

好的,我刚刚找到了解决方案。我的信号量方法实际上和调度组一样有效。任务只需要URLSession.shared.dataTask

仍然感谢所有答案。