Login credentials missing in swift UserDefaults - ios

I have an application which uses a rest api for authentication. The problem I am facing now is that I save user's token in my UserDefaults and username too because those are the two main parameters needed to get user details. so if the application is closed by the user he should still be able to view the view his profile when he opens the application back but instead the profile returns empty details. this is the UserDefaults codes that I have
let defaults = UserDefaults.standard
var isLoggedIn : Bool {
get {
return defaults.bool(forKey: LOGGED_IN_KEY)
}
set {
defaults.set(newValue, forKey: LOGGED_IN_KEY)
}
}
//Auth Token
var authToken: String {
get {
return defaults.value(forKey: TOKEN_KEY) as? String ?? ""
}
set {
defaults.set(newValue, forKey: TOKEN_KEY)
}
}
var userUsername: String {
get {
return defaults.value(forKey: USERNAME_KEY) as? String ?? ""
}
set {
defaults.set(newValue, forKey: USERNAME_KEY)
}
}
I have no idea why it isnt retrieving the user data.
My second question is when I logout the user, all the users details are cleared as expected but the moment I try loging in with a different user, the new user's authToken and details gets printed in the console but the user profile returns the profile of the previous person. which is not supposed to be. my code is shown below
func logoutUser() -> Void {
pk = 0
username = ""
email = ""
firstName = ""
lastName = ""
AuthService.instance.isLoggedIn = false
AuthService.instance.authToken = ""
AuthService.instance.userUsername = ""
}
#IBAction func logoutPressed(_ sender: Any) {
UserDataService.instance.logoutUser()
dismiss(animated: true, completion: nil)
}
I would also like to add that when i run the api using postman i get a response that "detail": "Signature has expired." so i had to input the new token in the header so it displays the user details again

enum SettingKeys: String {
case authToken
//...
}
struct Settings {
static var authToken: String? {
get { return UserDefaults.standard.string(forKey: SettingKeys.authToken.rawValue) }
set(value) { UserDefaults.standard.set(value, forKey: SettingKeys.authToken.rawValue) }
}
static func deleteAll(exclude: [SettingKeys] = []) {
let saveKeys = exclude.map({ $0.rawValue })
for key in UserDefaults.standard.dictionaryRepresentation().keys {
if !saveKeys.contains(key) {
UserDefaults.standard.removeObject(forKey: key)
}
}
}
}
I recommend storing keys as Enum, because then u can use it like that:
//Read
if let token = Settings.authToken {
//do something
}
//Write
Settings.authToken = "123456"
//Delete settings
Settings.deleteAll()
//or choose what to leave
Settings.deleteAll(exclude: [.authToken])
And it's worth to mention that defaults.synchronize() is deprecated.

Related

create user with xmppframework

I'm currently trying to setup a chat functionality by using ejabberd
I'm using the xmppframework to communicate with my ejabberd server.
What I'm trying to do is the following.
#IBAction func registerUser(_ sender: Any) {
var username: String = ""
var password: String = ""
let elements: NSMutableArray = []
if let user = tf_user.text {
username = "\(user)#192.168.1.19"
elements.add(XMLElement(name: "username", stringValue: username))
}
if let pass = tf_password.text {
password = pass
elements.add(XMLElement(name: "password", stringValue: password))
}
if username != "" && password != "" {
if stream.supportsInBandRegistration() {
do {
try stream.register(withElements: elements as! [Any])
} catch let error {
print(error)
}
}
}
}
However when I make the register call I get the following error
<iq xmlns="jabber:client" from="192.168.1.19" type="error">
<query xmlns="jabber:iq:register">
<username>user1#192.168.1.19</username>
<password>pass</password>
</query><error code="400" type="modify">
<bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Malformed username</text></error></iq>
I'm not sure why this isn't working. Does anyone know where I'm going wrong? I feel like it has something to do with adding my element.

Completion handler with POST request

I have simple login method which returns bool, depends on success of user login. I have problem with order of the responses and execution of the code. I've read about completion handlers, which I think are a solution to my problem but I'm not sure. Here is my method:
//perform user login in, setting nsuserdefaults and returning the bool result
func login(username: String, password:String) -> (Bool) {
var success:Bool = false
//sending inputs to server and receiving info from server
let postRequest = postDataToURL()
postRequest.link = "http://pnc.hr/rfid/login.php"
postRequest.postVariables = "username=" + username + "&password=" + pass
word
postRequest.forData("POST") { jsonString in
// getting the result from the asinhronys task
let result = convertStringToDictionary(jsonString as String)
if let loggedIn = result?["loggedIn"] as? Bool where loggedIn == true {
let userType = result?["userType"] as? String
let token = result?["token"] as? String
//if user is logged - setting parameters in Key Chains and redirecting them to the menu view
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(loggedIn, forKey: "loggedIn")
defaults.setObject(username, forKey: "username")
defaults.setObject(userType, forKey: "userType")
defaults.setObject(token, forKey: "token")
success = true
}
else {
success = false
}
print ("class - " + String(jsonString))
print ("classIN - " + String(success))
}
print ("classOUT - " + String(success))
return success
}
I would like to make return of success variable inside if statement which checks variable loggedIn is equal to true. But in that case I get error.
Then I have made this method. The problem is that method returns the variable success quicker than the POST request has been done. So it will be false in every case. I have printed variables to see the order of the code execution and method first prints the "classOUT", returns the variable, and then sets up variable value and print "classIN".
How can I wait until the code which logs user gets executed so I can get the right value of the variable success?
Perform user login in, setting nsuserdefaults and returning the bool result
completionBlock: is that block which will get executed when you call it like any block but you get to choose when and what all to pass through that block.
func login(username: String, password:String,completionBlock : ((success : Bool)->Void)){
//sending inputs to server and receiving info from server
let postRequest = postDataToURL()
postRequest.link = "http://pnc.hr/rfid/login.php"
postRequest.postVariables = "username=" + username + "&password=" + password
postRequest.forData("POST") { jsonString in
// getting the result from the asinhronys task
let result = convertStringToDictionary(jsonString as String)
if let loggedIn = result?["loggedIn"] as? Bool where loggedIn == true {
let userType = result?["userType"] as? String
let token = result?["token"] as? String
//if user is logged - setting parameters in Key Chains and redirecting them to the menu view
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(loggedIn, forKey: "loggedIn")
defaults.setObject(username, forKey: "username")
defaults.setObject(userType, forKey: "userType")
defaults.setObject(token, forKey: "token")
completionBlock(success:true)
}
else {
completionBlock(success:false)
}
}
}
when you call it would look something like this:-
login(username: String, password:String,completionBlock : { (success) in
print(success)
})
you could do something like this
func login(username: String, password: String, completion: (Bool) -> ()) {
... YOUR USUAL NETWORKING CODE ...
completion(success)
}
and then call it
login(username: anonymous, password: ******) { authStatus in
if authStatus == true {
print("user in")
} else {
print("try one more time")
}
}

Is there any way of sharing getter and setter through properties in Swift?

I'm building a helper to enable typed access to NSUserDefaults properties. Something like this:
struct UserDefaults {
private static var standardUserDefaults: NSUserDefaults = {
return NSUserDefaults.standardUserDefaults()
}()
private static let propKey = "PROP"
static var prop: Bool {
get {
return standardUserDefaults.boolForKey(propKey)
}
set {
standardUserDefaults.setBool(newValue, forKey: propKey)
standardUserDefaults.synchronize()
}
}
}
This way I can have a nice syntax for reading and writing to NSUserDefaults:
UserDefaults.prop // read
UserDefaults.prop = false // write
The problem is that there's a lot of boilerplate code for this, I need 10 lines for each aditional property.
Is there any way of reducing the amount of lines needed for each new property? Reusing getter and setter? Any kind of run time generator?
You can try wrapping the actual value in a class that handles all the dirty work for you:
class WrappedUserDefault<T> {
let key : String
let defaultValue : T
var value : T {
get {
if let value = UserDefaults.standardUserDefaults.objectForKey(key) as? T {
return value
} else {
return defaultValue
}
}
set {
if let value = newValue as? AnyObject {
UserDefaults.standardUserDefaults.setValue(value, forKey: key)
} else {
UserDefaults.standardUserDefaults.removeObjectForKey(key)
}
UserDefaults.standardUserDefaults.synchronize()
}
}
init(key:String, defaultValue:T) {
self.key = key
self.defaultValue = defaultValue
}
}
struct UserDefaults {
static let standardUserDefaults = NSUserDefaults.standardUserDefaults()
static let ready = WrappedUserDefault<Bool>(key:"ready", defaultValue: true)
static let count = WrappedUserDefault<Int>(key: "count", defaultValue: 0)
}
Then with just a little bit more code you wind up with:
UserDefaults.count.value++
UserDefaults.ready.value = true
UserDefaults.ready.value
If the verbosity of ready.value bothers you, you can somewhat hide that, although then you're back to you're back to having a fair amount of copy/paste code:
struct UserDefaults {
static let standardUserDefaults = NSUserDefaults.standardUserDefaults()
private static let readyWrapper = WrappedUserDefault<Bool>(key:"ready", defaultValue: true)
static var ready : Bool {
get { return readyWrapper.value }
set { readyWrapper.value = newValue }
}
}
At least in this case though, the copy/paste code is fairly trivial, so unlikely to need to be altered in the future.
I like David's answer much better, but here's another option. Drops your 10 lines per variable down to 5 (mainly because of new line removal...)
struct UserDefaults {
private static var standardUserDefaults: NSUserDefaults = {
return NSUserDefaults.standardUserDefaults()
}()
//Repeate these 5 lines for all new variables,
//changing the as? to the proper variable type
//Adding in a default value for the return in
//case the as? cast fails for any reason
private static let propKey = "PROP"
static var prop: Bool {
get { return (getVar(propKey) as? Bool) ?? false }
set { setVar(newValue, key:propKey) }
}
//The generic set/get
private static func getVar(key : String) -> AnyObject?
{
return standardUserDefaults.objectForKey(key)
}
private static func setVar(newValue : AnyObject, key : String)
{
if(newValue is Bool)
{
standardUserDefaults.setBool((newValue as? Bool)!, forKey: key)
}
//... More cases here
else if(newValue == nil)
{
standardUserDefaults.removeObjectForKey(key)
}
else
{
standardUserDefaults.setObject(newValue, forKey: key)
}
standardUserDefaults.synchronize()
}
}

NSUserDefaults Loosing Value in Swift

Update: I've tried changing setValue to setObject, and the same error occurred.Upon further investigation with breakpoints and the LLDB, they are nil before the controller is even presented. I'm not saving them right.
I'm trying to simply save a couple of strings of text, and display them on another view using Swift. I'm not sure why I'm having such a hard time. Here is how I'm trying to accomplish this:
VC1
#IBAction func registerTapped(sender : AnyObject)
// Save the login information
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setValue(username.text, forKey: "username")
defaults.setValue(password.text, forKey: "password")
if firstName.text.isEmpty == false {
defaults.setValue(firstName.text, forKey: "firstname")
}
if lastName.text.isEmpty == false {
defaults.setValue(lastName.text, forKey: "lastname")
}
let profileView = ProfileViewController()
self.presentViewController(profileView, animated: true, completion: nil)
}
}
Cool. That looks like the correct way to save strings in UITextFields based upon my research. So, I open up VC2 and try to load the saved text into the new UITextField's, like so:
override func viewDidLoad() {
super.viewDidLoad()
let defaults = NSUserDefaults.standardUserDefaults()
username.text = defaults.stringForKey("username")
password.text = defaults.stringForKey("password")
if let first = defaults.stringForKey("firstname")
{
firstName.text = first
}
if let last = defaults.stringForKey("lastname") {
lastName.text = last
}
}
I get the crash fatal error: unexpectedly found nil while unwrapping an Optional value. I've been digging through tutorials for hours and can't for the life of me figure out what I am doing wrong.
Is it because it an an optional? This is my LLDB output:
Your issue has nothing to do NSUserDefaults, whats nil are your labels username, password, etc. in your second controller.
You should add a segue to your button (the one with registerTapped) to show the second controller and remove the last two lines in registerTapped.
Break your code into steps and debug each one. Your code would crash if your outlet is nil or if the key/value pair doesn't exist. Check that both username and password (The text fields) are not nil, as well as that the defaults results aren't nil:
var text: String?
text = defaults.stringForKey("username")
if let text = text
{
if let username = username
{
username.text = text
}
else
{
println("username field is nil!")
}
}
else
{
println("defaults stringForKey("username") = nil!")
}
text = defaults.stringForKey("password")
if let text = text
{
if let password = password
{
password.text = text
}
else
{
println("password field is nil!")
}
}
else
{
println("defaults stringForKey("password") = nil!")
}

Check if UserDefault exists - Swift

I'm trying to check if the a user default exists, seen below:
func userAlreadyExist() -> Bool {
var userDefaults : NSUserDefaults = NSUserDefaults.standardUserDefaults()
if userDefaults.objectForKey(kUSERID) {
return true
}
return false
}
However, no mater what it will always return true even when the object doesn't exist yet? Is this the right way for checking existence ?
Astun has a great answer. See below for the Swift 3 version.
func isKeyPresentInUserDefaults(key: String) -> Bool {
return UserDefaults.standard.object(forKey: key) != nil
}
I copy/pasted your code but Xcode 6.1.1 was throwing some errors my way, it ended up looking like this and it works like a charm. Thanks!
func userAlreadyExist(kUsernameKey: String) -> Bool {
return NSUserDefaults.standardUserDefaults().objectForKey(kUsernameKey) != nil
}
Swift 5:
if UserDefaults.standard.object(forKey: "keyName") != nil {
//Key exists
}
Yes this is right way to check the optional have nil or any value objectForKey method returns AnyObject? which is Implicit optional.
So if userDefaults.objectForKey(kUSERID) have any value than it evaluates to true. if userDefaults.objectForKey(kUSERID) has nil value than it evaluates to false.
From swift programming guide
If Statements and Forced Unwrapping
You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to
true; if it has no value at all, it evaluates to false.
Now there is a bug in simulators than after setting key in userDefaults they always remain set no matter you delete your app.You need to reset simulator.
Reset your Simulator check this method before setting key in userDefaults or remove key userDefaults.removeObjectForKey(kUSERID) from userDefaults
and it will return NO.On devices it is resolved in iOS8 beta4.
This is essentially the same as suggested in other answers but in a more convenient way (Swift 3+):
extension UserDefaults {
static func contains(_ key: String) -> Bool {
return UserDefaults.standard.object(forKey: key) != nil
}
}
usage: if UserDefaults.contains(kUSERID) { ... }
Simple Code to check whether value stored in UserDefault.
let userdefaults = UserDefaults.standard
if let savedValue = userdefaults.string(forKey: "key"){
print("Here you will get saved value")
} else {
print("No value in Userdefault,Either you can save value here or perform other operation")
userdefaults.set("Here you can save value", forKey: "key")
}
Many of the solutions here are valid. Still, I think they solve the wrong problem.
Usually, code like this is used to check if a value is set so another default value can be used:
if isKeyPresentInUserDefaults(key: "username") {
return UserDefaults.standard.string(forKey: "username")
} else {
return "No username was set"
}
You shouldn't care if a key is set or not. There is a far more elegant approach for having default values in UserDefaults:
UserDefault.standard.register(defaults: ["username": "No username was set"])
If you run this code at app launch, subsequent calls to UserDefaults.standard.string(forKey: "username") will return the default value of "No username was set" if no value was set for the key yet.
for swift 3.2
func userAlreadyExist(kUsernameKey: String) -> Bool {
return UserDefaults.standard.object(forKey: kUsernameKey) != nil
}
public class PreferencesUtils {
private init() {
}
public static func setBoolData(boolValue: Bool, dataName: String) {
UserDefaults.standard.set(boolValue, forKey: dataName)
}
public static func getBoolData(dataName: String)-> Bool{
let defaults = UserDefaults.standard
if(defaults.value(forKey: dataName) != nil) {
return defaults.value(forKey: dataName)! as! Bool
} else {
return false
}
}
public static func saveStringData(data: String, dataName: String){
let preferences = UserDefaults.standard
preferences.set(data, forKey: dataName)
let didSave = preferences.synchronize()
if !didSave {
debugPrint("Not saved yet")
}
}
public static func getSavedStringData(dataName: String)-> String{
let defaults = UserDefaults.standard
if(defaults.value(forKey: dataName) != nil){
return defaults.value(forKey: dataName) as! String
} else {
return ""
}
}
public static func saveIntData(data : Int, dataName: String){
let preferences = UserDefaults.standard
preferences.set(data, forKey: dataName)
let didSave = preferences.synchronize()
if !didSave {
debugPrint("Not saved yet")
}
}
public static func getSavedIntData(dataName: String) -> Int {
let defaults = UserDefaults.standard
if(defaults.value(forKey: dataName) != nil){
return defaults.value(forKey: dataName) as! Int
}else{
return 0
}
}
}
Or you can try this library: Link
func keyExists(key: String) -> Bool {
guard let _ = UserDefaults.standard.object(forKey: key) {
return false;
}
return true;
}
override func viewDidLoad()
{
super.viewDidLoad()
if UserDefaults.standard.string(forKey: "CHARRY") == "CHARRY"{
lb.text = "CHARRY"
im.image = UIImage(named: "CHARRY")
}
}
#IBAction func PressedCar(_ sender: UIButton){
lb.text = "CHARRY"
im.image = UIImage(named: "CHARRY")
UserDefaults.standard.set("CAR", forKey: "CHARRY")
}

Resources