You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中URLSession.dataTask非抛出函数类型转换错误求助

解决Swift中URLSession闭包的抛出函数类型转换错误

嘿,刚看完你的问题,这个错误其实很常见——你在URLSession.dataTask的闭包里用了try,但这个闭包是非抛出型的,Swift不允许你直接把可能抛出错误的代码丢进去而不处理。咱们一步步来解决:

错误根源

JSONSerialization.jsonObject(with:options:)(你代码里用的是Swift 2的旧写法JSONObjectWithData)会抛出解析错误,但URLSession.shared.dataTask(with:completionHandler:)的闭包签名是(Data?, URLResponse?, Error?) -> Void,它不允许内部抛出未处理的错误。这就是你看到Invalid conversion from throwing function type...错误的核心原因。

解决方案:处理闭包内的抛出错误

你需要把try包裹在do-catch块里,或者用try?/try!来处理错误。同时还要修正代码里的一些旧Swift语法问题(比如NSUserDefaults、dismissViewControllerAnimated这些都是Swift 2的写法,现在Swift 3+已经更新了API)。

修正后的完整代码

import UIKit 

class LoginViewController: UIViewController { 
    @IBOutlet weak var userLoginTextField: UITextField! 
    @IBOutlet weak var userPasswordTextField: UITextField! 

    override func viewDidLoad() { 
        super.viewDidLoad() 
    } 

    override func didReceiveMemoryWarning() { 
        super.didReceiveMemoryWarning() 
    } 

    @IBAction func loginButtonTapped(_ sender: Any) { 
        // 安全解包输入框内容,避免强制解包崩溃
        guard let userLogin = userLoginTextField.text, !userLogin.isEmpty,
              let userPasswd = userPasswordTextField.text, !userPasswd.isEmpty else {
            print("用户名或密码不能为空")
            return
        } 

        // 构建网络请求
        guard let myUrl = URL(string: "https://www.pcpusa.net/legacy/iOS/userLogin.php") else {
            print("URL格式错误")
            return
        }
        var request = URLRequest(url: myUrl)
        request.httpMethod = "POST"
        let postString = "login=\(userLogin)&password=\(userPasswd)"
        request.httpBody = postString.data(using: .utf8)

        // 修正后的URLSession任务
        let task = URLSession.shared.dataTask(with: request) { data, response, error in 
            // 先处理网络请求本身的错误
            if let error = error {
                print("网络请求错误:\(error.localizedDescription)")
                return
            }

            // 处理JSON解析的抛出错误
            do {
                guard let responseData = data else {
                    print("服务器返回数据为空")
                    return
                }
                // Swift 3+的JSON解析API,移除了旧的error参数,改为抛出错误
                if let json = try JSONSerialization.jsonObject(with: responseData, options: []) as? NSDictionary {
                    if let resultValue = json["status"] as? String {
                        print("结果:\(resultValue)")
                        if resultValue == "Success" {
                            // 登录成功,保存登录状态(Swift 3+的UserDefaults写法)
                            UserDefaults.standard.set(true, forKey: "isUserLoggedIn")
                            UserDefaults.standard.synchronize()
                            // 关闭当前页面(Swift 3+的dismiss写法,必须在主线程执行UI操作)
                            DispatchQueue.main.async {
                                self.dismiss(animated: true, completion: nil)
                            }
                        }
                    }
                }
            } catch let parseError {
                print("JSON解析错误:\(parseError.localizedDescription)")
            }
        } 
        task.resume() 
    } 
}

关键修改点说明

  • 处理抛出错误:把JSON解析的try放在do-catch块里,捕获并处理解析错误,符合闭包的非抛出要求
  • 安全解包:用guard let替代强制解包!,避免空值导致的崩溃
  • 更新Swift API:把NSURL→URL、NSUserDefaults→UserDefaults、dismissViewControllerAnimated→dismiss(animated:completion:)等旧API替换为Swift 3+的标准写法
  • 主线程更新UI:dismiss是UI操作,必须放在主线程执行,所以用DispatchQueue.main.async包裹

额外提醒

  • 网络请求的闭包默认在后台线程执行,所有UI操作(比如页面跳转、弹窗)都要切回主线程
  • 尽量避免使用try!强制解析JSON,除非你100%确定服务器返回的格式不会出错,否则用do-catch或try?更安全
  • 务必处理data为空的情况,避免因为服务器返回空数据导致解析失败

内容的提问来源于stack exchange,提问作者Tobin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:33:26