Search code examples
iosauthenticationif-statementswift2instance-variables

NSNotificationCenter issue: Fatal error thrown


I am working on an authentication system. Currently I can pull the API data and authenticate the users. I used an NSNotificationCenter dictionary to store my values and I can print out the string message but my boolean value returns an optional. Also, I am not sure where I should remove my observer once I am done with it. How should I go about implementing it?

Code receiving user input

import UIKit

class LoginViewController: UIViewController {


@IBOutlet weak var usernameField: UITextField!

@IBOutlet weak var pwdField: UITextField!

@IBAction func loginBtn(sender: AnyObject) {

    let loginobj = Login(userName : self.usernameField.text!, passWord : self.pwdField.text!)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(LoginViewController.handlingAuthentication(_:)), name:"errorPresent", object: nil)
    loginobj.getRequest()

}

override func viewDidLoad() {
    super.viewDidLoad()

}

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

func handlingAuthentication(notification: NSNotification) {

    let dict = notification.object as! NSDictionary
    let errorFound = dict["error"]
    let errorMessage = dict["message"]
    print(errorFound)

    if((errorFound?.string)! == true){
         //initialize Alert Controller
        let alertController = UIAlertController(title: "Authentication error", message: errorMessage?.string, preferredStyle: .Alert)

        //Initialize Actions
        let okAction = UIAlertAction(title: "Ok", style: .Default){
                (action) -> Void in
                self.dismissViewControllerAnimated(true, completion: nil)
            }

        //Add Actions
        alertController.addAction(okAction)

        //Present Alert Controller
        self.presentViewController(alertController, animated: true, completion: nil)

    }
    else
    {
        NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isUserLoggedIn")

        NSUserDefaults.standardUserDefaults().synchronize()

        self.dismissViewControllerAnimated(true, completion:nil)

    }

}

}

Code processing data handling for LoginViewController

import Foundation
import Alamofire
import SwiftyJSON
import RealmSwift

class Login {

init(userName: String, passWord: String) {
    Data.sharedInstance.userName = userName
    Data.sharedInstance.passWord = passWord
}

// call this method to login
func getRequest() {

    Alamofire.request(.POST, Data.todoEndpoint, parameters: ["username": Data.sharedInstance.userName!, "password": Data.sharedInstance.passWord!])
        .responseJSON { response in

            var errorFound = Bool()
            var errorMessage = String()

            if let result = response.result.value
            {
                let value = JSON(result)
                var outcome = String()

                //No username
                if value["password"] == nil && value["message"] == nil && value["name"] == nil
                {
                      errorFound = true
                      outcome = "No username: \(value)"
                      errorMessage = outcome
                }
                //No password
                else if value["username"] == nil && value["message"] == nil
                {
                    errorFound = true
                    outcome = "No password: \(value)"
                    errorMessage = outcome
                }
                //No password/ username
                else if value["username"] == nil && value["password"] == nil && value["message"] != nil
                {
                    outcome = "Incorrect cred: \(value)"
                    errorFound = true
                    errorMessage = outcome
                }
                //success
                else if value["username"] != nil && value["password"] == nil && value["message"] == nil
                {
                    errorFound = false
                    if let api_key = value["api_token"].string
                    {
                        print("The token is " + api_key)
                    }
                    else
                    {
                        print("error parsing api token")
                    }
                    //pass data to Users class
                    _ = Users.init(Name: value["name"].string, Email: value["email"].string, Id: value["id"].int, ProfilePicture: value["profile_picture"].string, Username: value["username"].string)
                    NSNotificationCenter.defaultCenter().removeObserver(self, name: "errorPresent", object: nil)

                }
                else
                {
                    errorFound = true
                    outcome = "No password and username: \(value)"
                    errorMessage = outcome

                }

            }
            else
            {
                print("JSON data is nil.")
            }

                let errorDict = ["error": errorFound, "message": errorMessage]

                NSNotificationCenter.defaultCenter().postNotificationName("errorPresent", object:errorDict)

    }

}


}

Solution

  • There are two reasons why you are not receiving your desired boolean outcome:

    • The way you handle data passed is wrong

    In your handlingAuthentication method, you should be doing this instead:

    func handlingAuthentication(notification: NSNotification) {
    
        let dict = notification.object as! NSDictionary
    
            if dict["error"]! as! Bool == true {
    
                let errorMessage = dict["message"] as! String
    
                //initialize Alert Controller
                let alertController = UIAlertController(title: "Authentication error", message: errorMessage, preferredStyle: .Alert)
    
                //Initialize Actions
                let okAction = UIAlertAction(title: "Ok", style: .Default){
                        (action) -> Void in
                        self.dismissViewControllerAnimated(true, completion: nil)
                }
    
                //Add Actions
                alertController.addAction(okAction)
    
                //Present Alert Controller
                self.presentViewController(alertController, animated: true, completion: nil)
    
             }
    
             else
    
             {
    
                    NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isUserLoggedIn")
    
                    NSUserDefaults.standardUserDefaults().synchronize()
    
                    self.dismissViewControllerAnimated(true, completion:nil)
    
             }
    
    }
    

    Where let errorMessage = dict["message"] as! String and dict["error"]! as! Bool == true would remove the optionals from your output

    • The way you handle JSON is incorrect. From what I can understand from your other posts, the data you are looking for are in the form of an array.

    This is what you should have done to obtain the values for your password and username errors:

     errorMessage = value["password"][0].string!
     errorMessage = value["username"][0].string!