【问题标题】:unwrapping an Optional value展开可选值
【发布时间】:2018-09-13 16:10:30
【问题描述】:

我正在尝试使用代码登录 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

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

【问题讨论】:

  • [13/Sep/2018 15:52:22] 终端上的“POST /api/social/convert-token/HTTP/1.1”400 214
  • 那么显然jsonData["access_token"] 为零?
  • 如何适应
  • 修复崩溃(这是因为强制展开)或修复为什么jsonData["access_token"].string 为零?那是不同的。

标签: ios json swift facebook alamofire


【解决方案1】:

首先,在任何地方都使用 force unwrap (!) 是一种不好的做法。尽量避免它,直到你真的需要它和/或知道你在做什么。在这里你使用 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/

【讨论】:

  • 我使用了你的第一个选项,效果很好!非常感谢,这个问题困扰我好久了
【解决方案2】:

当您有 !force unwrap 符号)时会发生此错误,这意味着您确定数据会在那里;但事实上,数据并不存在——它是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

Basics 部分的Optional Binding 下的 Swift 编程语言 (Swift 4.2) 指南中了解如何使用 if let 处理可能的 nil 值。

在指南的控制流部分的Early Exit下以及Statements中了解guard语句参考部分。

【讨论】:

    猜你喜欢
    • 2018-11-30
    • 2021-06-30
    • 2015-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多