解开可选值的包装



我正在尝试使用代码使用macbook登录,但不断收到此错误:

线程 1:致命错误:解开可选值时意外发现 nil

// API to log an user in
func login(userType: String, completionHandler: @escaping (NSError?) -> Void) {
let path = "api/social/convert-token/"
let url = baseURL!.appendingPathComponent(path)
let params: [String: Any] = [
"grant_type": "convert_token",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"backend": "facebook",
"token": FBSDKAccessToken.current().tokenString,
"user_type": userType
]
Alamofire.request(url!, method: .post, parameters: params, encoding: URLEncoding(), headers: nil).responseJSON { (response) in
switch response.result {
case .success(let value):
let jsonData = JSON(value)
self.accessToken = jsonData["access_token"].string!
self.refreshToken = jsonData["refresh_token"].string!
self.expired = Date().addingTimeInterval(TimeInterval(jsonData["expire_in"].int!))
completionHandler(nil)
break
case .failure(let error):
completionHandler(error as NSError?)
break
}
}
}

错误引用了以下行:

self.accessToken = jsonData["access_token"].string!

这是LoginViewController代码:

import UIKit
import FBSDKLoginKit
class LoginViewController: UIViewController {
@IBOutlet weak var bLogin: UIButton!
@IBOutlet weak var bLogout: UIButton!
var fbLoginSuccess = false
var userType: String = USERTYPE_CUSTOMER
override func viewDidLoad() {
super.viewDidLoad()
if (FBSDKAccessToken.current() != nil) {
bLogout.isHidden = false
FBManager.getFBUserData(completionHandler: {
self.bLogin.setTitle("Continue as (User.currentUser.email!)", for: .normal)
// self.bLogin.sizeToFit()
})
}
}
override func viewDidAppear(_ animated: Bool) {
if (FBSDKAccessToken.current() != nil && fbLoginSuccess == true) {
performSegue(withIdentifier: "CustomerView", sender: self)
}
}
@IBAction func facebookLogout(_ sender: AnyObject) {
APIManager.shared.logout { (error) in
if error == nil {
FBManager.shared.logOut()
User.currentUser.resetInfo()
self.bLogout.isHidden = true
self.bLogin.setTitle("Login with Facebook", for: .normal)
}
}
}
@IBAction func facebookLogin(_ sender: AnyObject) {
if (FBSDKAccessToken.current() != nil) {
APIManager.shared.login(userType: userType, completionHandler:  { (error) in
if error == nil {
self.fbLoginSuccess = true
self.viewDidAppear(true)
}
})
} else {
FBManager.shared.logIn(
withReadPermissions: ["public_profile", "email"],
from: self,
handler: { (result, error) in
if (error == nil) {
FBManager.getFBUserData(completionHandler: {
APIManager.shared.login(userType: self.userType, completionHandler:  { (error) in
if error == nil {
self.fbLoginSuccess = true
self.viewDidAppear(true)
}
})
})
}
})
}
}
}

斯威夫特 3 Xcode 9 iOS 10.2

我阅读了几篇文章以找出此类错误的原因,但没有成功。

首先,在任何地方都使用强制解包(!(是一种不好的做法。尽量避免它,直到你真的需要它和/或知道你在做什么。在这里,您使用 SwiftyJSON。它可以帮助您以方便的方式从 JSON 中提取数据。但是你不应该依赖,你总是会从后端获得正确的JSON。它返回错误的 JSON 并且不需要值的原因有很多。有两种选择:

  1. 您可以使用.stringValue代替.string- 它将返回一个空字符串而不是nil
  2. 你可以这样做:if let token = jsonData["access_token"].string {...}甚至使用guard语句

这是一篇了解强制展开的好文章:https://blog.timac.org/2017/0628-swift-banning-force-unwrapping-optionals/

当您有一个!(强制解包符号(时,会发生此错误,这意味着您确定数据将在那里; 但事实上,数据不存在 - 它是nil

尝试使用guard语句。例如:

guard let self.accessToken = jsonData["access_token"].string else {
// log error message, if desired; then exit the function
return
}

或者,您可以使用if let语句:

if let self.accessToken = jsonData["access_token"].string {
// do stuff if 'jsonData["access_token"].string' is valid
}
else {
// do other stuff if 'jsonData["access_token"].string' is nil
}

现在,为什么数据不存在(nil( - 这是另一个问题。也许检查您的JSON函数以确保它正确处理 JSON 响应。此外,请检查以确保您得到的有效响应:

guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode == 200 else {
// handle a bad response code
return
}
// handle the good response code stuff after the guard statement

在《Swift编程语言 (Swift 4.2( 指南》的">基础知识"部分的"可选绑定"下,了解如何使用if let处理可能的nil值。

了解指南的">控制流"部分的"提前退出"下的guard语句,以及"参考"的"语句"部分。

最新更新