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
相关产品推荐
相关产品推荐

