Here is my code in a swift file to keep token in user device:
struct DefaultsKeys
{
static let token = ""
}
class DataContainerSingleton
{
static let sharedDataContainer = DataContainerSingleton()
var token: String?
var goToBackgroundObserver: AnyObject?
init()
{
let defaults = UserDefaults.standard
token = defaults.object(forKey: DefaultsKeys.token) as! String?
goToBackgroundObserver = NotificationCenter.default.addObserver(
forName: NSNotification.Name.UIApplicationDidEnterBackground,
object: nil,
queue: nil)
{
(note: Notification!) -> Void in
let defaults = UserDefaults.standard
defaults.set( self.token, forKey: DefaultsKeys.token)
defaults.synchronize()
}
}
}
Then when I get the token from Alamofire request I save it as :
DataContainerSingleton.sharedDataContainer.token = usertoken
but when I go to viewdidload and check if DataContainerSingleton.sharedDataContainer.token != nil it return nil after I re-run the project! even when I print DataContainerSingleton.sharedDataContainer.token it prints nil!
Where is my mistake pleas
Edit:
here is what I've tried but it returns nil #Paulw11
`struct DefaultsKeys
{
static let token = "token"
}
class DataContainerSingleton
{
static let sharedDataContainer = DataContainerSingleton()
var token: String? {
didSet {
let defaults = UserDefaults.standard
defaults.set(token, forKey:DefaultsKeys.token)
defaults.synchronize()
}
}
}`
Why are you using all of this complicated logic? Saving to NSUserDefaults is low impact; you should simply save it in a didSet for the token property. Also, make sure you load the value back when you initialise your class.
class DataContainerSingleton
{
static let sharedDataContainer = DataContainerSingleton()
var token: String? {
didSet {
let defaults = UserDefaults.standard
defaults.set(token, forKey:DefaultsKeys.token)
}
}
init() {
let defaults = UserDefaults.standard
self.token = defaults.object(forKey:DefaultsKeys.token) as? String
}
}
Also, you need to provide a key name for your default:
struct DefaultsKeys
{
static let token = "token"
}
Related
I'm trying to save a custom class array to UserDefaults but it doesn't work. I get nil back on if let. I looked everywhere online. I'm using Swift 4.2
extension UserDefaults {
func saveReciters(_ reciters: [Reciter]) {
do {
let encodedData = try NSKeyedArchiver.archivedData(withRootObject: reciters, requiringSecureCoding: false)
self.set(encodedData, forKey: UD_RECITERS)
} catch {
debugPrint(error)
return
}
}
func getReciters() -> [Reciter] {
if let reciters = self.object(forKey: UD_RECITERS) as? Data {
return NSKeyedUnarchiver.unarchiveObject(with: reciters) as! [Reciter]
} else {
print("EMPTY RECITERS")
return [Reciter]()
}
}
}
UserInfo={NSDebugDescription=Caught exception during archival: -[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x600001babcc0
Thats my class:
class Reciter: NSCoding {
private(set) public var name: String
private(set) public var image: UIImage?
private(set) public var surahs: [Surah]
private(set) public var documentID: String
private let quranData = QuranData()
init(name: String, image: UIImage?, surahCount: Int?, documentID: String) {
self.name = name
self.image = image
self.documentID = documentID
if let surahCount = surahCount {
surahs = Array(quranData.getAllSurahs().prefix(surahCount))
} else {
surahs = quranData.getAllSurahs()
}
}
func encode(with aCoder: NSCoder) {
}
required init?(coder aDecoder: NSCoder) {
}
}
On my Surah class i get nil back. All other properties i get back succesfully
Most often I see developer's use codeable, here I am using user as an example:
YourDataModel.swift
struct User: Codable {
var userId: String = ""
var name: String = ""
var profileImageData: Data? }
UserDefaults.swift
import Foundation
extension UserDefaults {
/// The current user of the application, see `./Models/User.swift`
var currentUser: User? {
get {
guard let userData = self.object(forKey: #function) as? Data else { return nil }
return try? JSONDecoder().decode(User.self, from: userData)
}
set {
guard let newuser = newValue else { return }
if let userData = try? JSONEncoder().encode(newuser) {
self.set(userData, forKey: #function)
}
}
}
}
Transform the data into json data... #function is the function or value name i.e.
// For the case the user doesn't yet exist.
if ( UserDefaults.standard.currentUser == nil ) {
// Create a new user
user = User()
// Generate an id for the user, using a uuid.
user?.userId = UUID().uuidString
} else {
// otherwise, fetch the user from user defaults.
user = UserDefaults.standard.currentUser
}
I'm trying to save dictionary into UserDefaults And then I want to fetch data or delete.
class userDefaultsManager {
static func getAllUsers()->[UserModel]{
if let all = UserDefaults.standard.array(forKey: "usersKey") as? [Dictionary<String,Any>] {
return all.map{UserModel.init(dictionary: $0)}
}
return []
}
static func insertUser(name:String, email:String)->Bool {
let newUserModel = UserModel.init(name: name, email: email)
var all = getAllUser()
all.append(newUserModel)
UserDefaults.standard.set(all.map{$0.dictionary}, forKey: "usersKey")
return UserDefaults.standard.synchronize()
}
static func deleteUser(email:String)->Bool {
var all = getAllUser()
let index = all.index{$0.email == email}
if index != nil {
all.remove(at: index!)
UserDefaults.standard.set(all.map{$0.dictionary}, forKey: "usersKey")
UserDefaults.standard.synchronize()
return true
} else {
return false
}
}
}
class UserModel:NSObject{
var name: String!
var email: String!
init(name:String, email:String) {
self. name = name
self. email = email
super.init()
}
init(dictionary:[String:Any]) {
self.name = ""
self.email = ""
super.init()
self.setValuesForKeys(dictionary)
}
var dictionary:[String:Any] {
return self.dictionaryWithValues(forKeys: ["name","email"]) //Error here
}
}
The code working on swift 3 but I got error with swift 4 on var dictionary:[String:Any]
here is the error:
implicit Objective-C entrypoint -[Myapp.UserModel name] is
deprecated and will be removed in Swift 4
Please any help to fix this will be appreciated.
Your classes inherited from NSObject, and using objc KVC, it was fine for Swift3, because Swift3 assumed all NSObject subclasses as #objc by default, in Swift4 you need to declare your accessors #objc to make them available for obj-c KVC operations.
https://forums.developer.apple.com/thread/81789
When I try to save to NSUserDefaults by adding a setter to my class variable (in this case the id and authToken variables, the values don't seem to be saved. When I run with a breakpoint on, the getter of id and authToken always return nil even after setting them with a value.
class CurrentUser {
static let defaultInstance = CurrentUser()
func updateUser(id id: String, authToken: String) {
self.id = id
self.authToken = authToken
}
var authToken: String? {
get {
if let authToken = NSUserDefaults.standardUserDefaults().objectForKey("userAuthToken") {
return (authToken as! String)
} else {
return nil
}
}
set {
NSUserDefaults.standardUserDefaults().setObject(authToken, forKey: "userAuthToken")
NSUserDefaults.standardUserDefaults().synchronize()
}
}
var id: String? {
get {
if let id = NSUserDefaults.standardUserDefaults().objectForKey("userId") {
return (id as! String)
} else {
return nil
}
}
set {
NSUserDefaults.standardUserDefaults().setObject(id, forKey: "userId")
NSUserDefaults.standardUserDefaults().synchronize()
}
}
}
However, when I pull the lines out to the updateUser function (one level higher), all works as expected.
class CurrentUser {
static let defaultInstance = CurrentUser()
func updateUser(id id: String, authToken: String) {
NSUserDefaults.standardUserDefaults().setObject(id, forKey: "userId")
NSUserDefaults.standardUserDefaults().synchronize()
NSUserDefaults.standardUserDefaults().setObject(authToken, forKey: "userAuthToken")
NSUserDefaults.standardUserDefaults().synchronize()
}
var authToken: String? {
get {
if let authToken = NSUserDefaults.standardUserDefaults().objectForKey("userAuthToken") {
return (authToken as! String)
} else {
return nil
}
}
}
var id: String? {
get {
if let id = NSUserDefaults.standardUserDefaults().objectForKey("userId") {
return (id as! String)
} else {
return nil
}
}
}
}
Why would this be? What am I missing? Does the { set } run on a different thread / mode where NSUserDefaults isn't accessible?
You must use newValue inside set method, value is still nil, or use didSet and then you can use variable.
As Alex said, you must use newValue in set method. Moreover, you can refer to this link for more detail:
Store [String] in NSUserDefaults (Swift)
I'm writing a DataService that interfaces with Firebase. I'm setting self.realID within a closure and when I reference it outside the closure, it fails because it unwraps a nil value. Why is this happening?
My file:
import Foundation
import Firebase
class Database {
var firebaseRef = Firebase(url:"https://<<UNIQUE>>.firebaseio.com")
class var sharedInstance: Database {
struct Data {
static var instance: Database?
static var token: dispatch_once_t = 0
}
dispatch_once(&Data.token) {
Data.instance = Database()
}
return Data.instance!
}
var uid : String!
var realID : String!
var validated = false
func validate(user: String, study: String) -> Bool {
firebaseRef.authUser(user+"#example.com", password: user,
withCompletionBlock: { error, authData in
if error != nil {
NSLog(String(error))
} else {
self.uid = authData.uid
NSLog(authData.uid)
}
})
let usersRef = Firebase(url: "https://<<UNIQUE>>.firebaseio.com/users")
usersRef.observeEventType(FEventType.Value, withBlock: { (snapshot) in
let value = snapshot.value.objectForKey("study") as! String
self.realID = value
NSLog(self.realID) // this is a non-nil value
})
NSLog("About to encounter nil value and crash")
if self.realID == study {
return true
}
return false
}
}
How do i prevent this fatal error from happening?
You need to add a completionHandler because it is async request. If you will set the break points then return is executed before you are setting the id.
func validate(user: String, study: String, completionHandler:(Bool) -> Void) {
let usersRef = Firebase(url: "https://<<UNIQUE>>.firebaseio.com/users")
usersRef.observeEventType(FEventType.Value, withBlock: { (snapshot) in
if let value = snapshot.value.objectForKey("study") as? String {
self.realID = value
completionHandler(true)
} else {
completionHandler(false)
}
})
}
UPDATE
validate("Rahul", study: "Study") { (value: Bool) in
if value {
} else {
}
}
I have a User Struct that I'm casting to Json to be able to get into NSUserDefaults...
import Foundation
struct User {
var name = ""
var stores: [Store] = []
init?(json: [String: AnyObject]) {
if let name = json["name"] as? String,
storesJSON = json["stores"] as? [[String: AnyObject]]
{
self.name = name
self.stores = storesJSON.map { Store(json: $0)! }
} else {
return nil
}
}
init() { }
func toJSON() -> [String: AnyObject] {
return [
"name": name,
"stores": stores.map { $0.toJSON() }
]
}
}
and I am using a Data Manager class (Singleton) to add a new User. But I can't figure out what to pass into updateValue in my addPerson function below? Alternatively is there another way to get this object into NSUserDefaults?
import Foundation
class DataManager {
static let sharedInstance = DataManager()
var users = [String : User]()
init() {
let userDefaults = NSUserDefaults.standardUserDefaults()
if let var userFromDefaults = userDefaults.objectForKey("users") as? [String : User] {
users = userFromDefaults
}
else {
// add default values later
}
}
var userList: [String] {
var list: [String] = []
for userName in users.keys {
list.append(userName)
}
list.sort(<)
return list
}
func addPerson(newUserName: String) {
users.updateValue(User(), forKey: newUserName)
// saveData()
}
You should change your interface of the addPerson function, use addPerson(newUser: User) instead of using addPerson(newUserName: String) as #iosDev82 said:
// Because your addPerson function needs two parameters: a name and a user object
func addPerson(newUser: User) {
users.updateValue(newUser, forKey: newUser.name)
// saveData()
}
so you can:
let newName = textField.text.capitalizedString
let newUser = User(["name": newName, "stores" : []])
DataManager.sharedInstance.addPerson(newUser)
I think you already know how to create a User object. And that is what you should pass as an argument to your following function. Something like this.
var aUser = User(["name": textField.text. capitalizedString])
DataManager.sharedInstance.addPerson(aUser)
func addPerson(newUser: User) {
users[newUser.name] = newUser
// saveData()
}