Разворачивание необязательного значения

Я пытаюсь войти в систему с macbook, используя код, но продолжаю получать эту ошибку:

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

// 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)
                                }
                            })
                        })
                    }
            })
        }
    }
}

Swift 3 Xcode 9 iOS 10.2

Я прочитал несколько текстов, чтобы выяснить причины этого типа ошибок, но безуспешно.

[13 / сен / 2018 15:52:22] "POST / api / social / convert-token / HTTP / 1.1" 400 214 на терминале

Saad Tlh 13.09.2018 18:14

Значит, очевидно, что jsonData["access_token"] равен нулю?

Larme 13.09.2018 18:20

как вписаться в это

Saad Tlh 13.09.2018 18:41

Исправить сбой (из-за принудительного развертывания) или исправить, почему значение jsonData["access_token"].string равно нулю? Это другое.

Larme 13.09.2018 18:42
1
4
494
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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/

Я использовал 1-й вариант, и он отлично работает! спасибо большое, давно мучаюсь с этой проблемой

Saad Tlh 15.09.2018 03:06

Эта ошибка возникает, когда у вас есть ! (символ принудительно развернуть), что означает, что вы уверены, что данные будут там; но на самом деле данных нет - это 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

Узнайте об использовании if let для обработки возможных значений nil в Руководстве по языку программирования Swift (Swift 4.2) в разделе Дополнительная привязка в разделе Основы.

Узнайте о операторах guard в разделе Ранний выход в разделе Поток управления Руководства, а также в разделе Заявления Справочного руководства.

Другие вопросы по теме