Swift URL 会话和 URL 请求不起作用

Posted

技术标签:

【中文标题】Swift URL 会话和 URL 请求不起作用【英文标题】:Swift URL Session and URL Request not working 【发布时间】:2017-07-31 00:35:26 【问题描述】:

我遇到了与this post 非常相似的问题,但我并不完全理解答案。我创建了一个完成处理程序,但它似乎没有按预期工作。

func updateTeam(teamID: Int) 
    startConnection NSArray, Int in
        //Do things with NSArray
    


func startConnection(completion: (NSArray, Int) -> Void) 
    let url = URL(string: "http://www.example.com/path")
    var request : URLRequest = URLRequest(url: url!)
    request.httpMethod = "POST"
    let postString = "a=\(Int(teamInput.text!)!)"
    request.httpBody = postString.data(using: .utf8)

    let dataTask = URLSession.shared.dataTask(with: request) 
        data,response,error in
        print("anything")
        do 
            if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary 
                self.teamResult = jsonResult
                print(jsonResult)
            
         catch let error as NSError 
            print(error.localizedDescription)
        

    
    dataTask.resume()

    completion(NSArray(object: teamResult), Int(teamInput.text!)!)

dataTask 语句中似乎没有运行,或者至少在我尝试使用结果数据之前它没有完成。这个完成处理程序有什么问题?

提前谢谢你!

【问题讨论】:

我认为completion(NSArray(object: teamResult), Int(teamInput.text!)!) 应该去你拥有print(jsonResult) 的地方。现在的方式是,您启动数据任务,然后立即使用(可能)nil 调用完成处理程序。如果您在数据任务处理程序中(在任何打印方法上)设置断点,断点是否命中? 我强烈建议您查找 Alamofire 并在可能的情况下将其用于此项目,它使这样的代码更容易编写 是的,将处理程序移至数据任务似乎效果很好。非常感谢! @Daniel Legler,我一定会调查的 【参考方案1】:

您的代码结构不正确。

URLSession 创建异步运行的任务。你设置一个任务,或者传入一个完成块,或者设置一个委托。

task.resume() 调用立即返回,远在网络下载完成之前。

任务完成后,系统会调用您的完成处理程序(或您的委托,如果您使用委托样式)。

请注意,URLSessions 的完成处理程序和委托调用是在后台线程上完成的。如果您为响应任务完成而执行任何 UIKit 调用,则需要在主线程上执行。

正如@keithbhunter 在他的评论中所说,您需要将对您的完成处理程序的调用放在您的任务的完成处理程序中。如果您将整个完成处理程序调用包装在对主线程的调用中,这可能是最安全的:

func startConnection(completion: (NSArray, Int) -> Void) 
    let url = URL(string: "http://www.example.com/path")
    var request : URLRequest = URLRequest(url: url!)
    request.httpMethod = "POST"
    let postString = "a=\(Int(teamInput.text!)!)"
    request.httpBody = postString.data(using: .utf8)

    let dataTask = URLSession.shared.dataTask(with: request) 
        data,response,error in
        print("anything")
        do 
            if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary 
                self.teamResult = jsonResult
                print(jsonResult)
                //Use GCD to invoke the completion handler on the main thread
                DispatchQueue.main.async() 
                  completion(NSArray(object: teamResult), Int(teamInput.text!)!)
                
            
         catch let error as NSError 
            print(error.localizedDescription)
        
    
    dataTask.resume()

请注意,您对 teamInput.text 的强制解包非常脆弱,如果 teamInput.text 为 nil 或无法转换为 Int,则会崩溃。你最好编写你的完成处理程序来为你从 teamInput.text 返回的数据和 int 值取可选项:

func startConnection(completion: (NSArray?, Int?) -> Void) 

并通过可选参数调用它:

let value: Int? = teamInput.text != nil ? Int(teamInput.text!) : nil
completion(NSArray(object: teamResult), value)

【讨论】:

【参考方案2】:

我认为您还应该在关闭时处理错误。

func updateTeam(teamID: Int) 
    startConnection array, teamId, error in
        // Do things with NSArray or handle error
    


func startConnection(completion: @escaping (NSArray?, Int, Error?) -> Void) 
    let url = URL(string: "http://www.example.com/path")
    var request : URLRequest = URLRequest(url: url!)
    request.httpMethod = "POST"
    let postString = "a=\(Int(teamInput.text!)!)"
    request.httpBody = postString.data(using: .utf8)

    let dataTask = URLSession.shared.dataTask(with: request) 
        data,response,error in
        print("anything")
        do 
            if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary 
                self.teamResult = jsonResult
                print(jsonResult)
                DispatchQueue.main.async() 
                    completion(NSArray(object: self.teamResult), Int(teamInput.text!)!, nil)
                
         catch let error as NSError 
            print(error.localizedDescription)
            DispatchQueue.main.async()   
                completion(nil, Int(teamInput.text!)!, error)
            
        

    
    dataTask.resume()

【讨论】:

请注意,OP 对 teamInput 的强制解包也是危险的。看我的回答...【参考方案3】:

试试这个:

let urlString = "www.yoururl.com"
let url = URL(string: string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)

这对我有很多帮助

【讨论】:

以上是关于Swift URL 会话和 URL 请求不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Swift4 url​​Session Decodable 中的 POST 方法不起作用(这里出了啥问题?)

除了烧瓶应用程序的 url 之外,Flask 会话在另一个 url 中不起作用

Spring SAML - 点击 URL '/saml/logout' 后全局注销不起作用

Seo 友好 URL 导致 CSS IMG 和 JS 不起作用

PHP未设置会话不起作用

Codeigniter - 注销链接不起作用 - 会话和 cookie 未销毁