Storing class in NSUserDefaults and accessing in next view - ios

I created a swift class called UserDetails and below is the structure:
import Foundation
class UserDetailsClass {
var fullname: String!
var mobile: String!
var email: String!
var password: String!
}
In my current View controller , I create an instance and store the values I want to move to next view in the instance variables as shown below:
var userDetailsInstance = UserDetailsClass()
userDetailsInstance.fullname = fullNameTextField.text
userDetailsInstance.mobile = mobileTextField.text
userDetailsInstance.email = emailTextField.text
userDetailsInstance.password = passwordTextField.text
var prefs = NSUserDefaults.standardUserDefaults()
prefs.setObject(userDetailsInstance, forKey: "currentGuest")
prefs.synchronize()
In the next view (where there is segue connected, I try to do this:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var prefs = NSUserDefaults.standardUserDefaults()
var userDetailsClass: AnyObject? = prefs.valueForKey("currentGuest")
}
but the app immediately crashes. The objective here is that after user enters his/her details, i do not store them in server but rather in the NSUserDefault then take them to the next view where an SMS verification would take place. Once the verification is done, I would store the information on the server.
the error console is showing:
Attempt to insert non-property list object appName.UserDetailsClass
for key currentGuest'
Is there a better way to move the data than storing an object in NSUserDefault?
I am a beginner iOS developer so thanks for your help.

The reason you are unable to store the object in NSUserDefaults is because it is not a property list type (NSNumber, NSData, NSArray, NSDictionary, NSDate, String, Bool). To store it in NSUserDefaults, it must be one of these types so you could serialize it to NSData, but in order to do that it would need to be NSCoding compliant.
The better solution is to pass the object in prepareForSegue

NSUserDefaults doesn't support saving custom classes.
You should convert your UserDetailsClass to Dictonary and save dictionary to NSUserDefaults.

Related

How to convert Firebase result to List in SwiftUI

I wanted to make a list in swiftui from firebase data. So here's my UI
I've already make a data for that username "mike_one", and it's perfectly working,
this is my xcode result
{
IC2ol5bimucKu2d89u2YBz0Bqot2 = {
name = mike;
photo = "https://firebasestorage.googleapis.com/v0/b/instagram-ios-1ed09.appspot.com/o/photo%2Fa2.jpg?alt=media&token=9b6c58f1-eedc-4190-bc63-3f3325c84d77";
username = "mike_one";
};}
And this is my database
So what i'm asking right now is, How to make the result of the database to be a model? so I can use it as a list.
Please help me.
I appreciate your answer!
Strictly speaking, it would not be possible to convert textual firebase data to a List object. A SwiftUI List is defined as
A container that presents rows of data arranged in a single column
in other words it's a UI element, not a data element.
That being said a List is often backed by an Array or other data storage element. So you'll read Firebase data and store that in an array. Then that array backs your UI List object.
In this case, I would suggest creating a UserClass to hold the Firebase data
class UserClass {
var name = ""
var photoUrl = ""
var username = ""
}
and then array to store your users in
var userArray = [UserClass]()
then as data is read from Firebase, create the user objects and populate the array. Your Firebase code wasn't included so in brief
firebase.observe.... { snapshot in
let user = UserClass()
...populate user properites from the snapshot
self.userArray.append(user)
}
Then in your view, access the array elements to show them in the List object
struct ContentView: View {
var body: some View {
List(userArray) { user in
//do something with each user object
// like Text(user.username)
}
}
}

Retrive specific data from firebase in Swift

Hi i have this structure of firebase database:
I need to retrive the specific data: Shane/DatiUtente/Password from the database and add it into a string var
please someone can tell me how is possible.
Sorry for my english if is bad i'm italian :)
You are going to need to parse through your database and retrieve the value you want. It would be something like this:
//At the top of your class set an empty variable like this:
var pass = String()
//Say for example you want to display that password to a label on your storyboard
#IBOutlet weak var passLbl: UILabel!
//Inside your viewDidLoad function you would want to add this:
DBRef.child("Shane").child("DatiUtente").child("Password").observeSingleEvent(of: .value, with: { (snaps) in
if let dictionary = snaps.value as? [String: AnyObject] {
self.passLbl.text = dictionary["pass"] as? String }
// IF you want it to the string as you asked
replace the self.passLbl.text with the empty pass variable you created at the top.

iOS: Core Data fails to save when attribute is a double

I thought I'd ask here first before I sent my laptop flying out of the window. I am very new to iOS development and have been toying around with Core Data trying to create an expense manager app. I have a single entity named "Account" which has two non-optional attributes (name and initBalance) as follows:
I have also created an NSManagedObject subclass as follows:
//Account.swift
class Account: NSManagedObject {
override func awakeFromInsert() {
super.awakeFromInsert()
initBalance = NSNumber(double: 0.0)
name = ""
}
}
//Account+CoreDataProperties.swift
extension Account {
#NSManaged var initBalance: NSNumber
#NSManaged var name: String
}
The Account entities are presented in the AccountsViewController (a subclass of UITableViewController conforming to the NSFetchedResultsControllerDelegate protocol) using an NSFetchedResultsController. To add a new Account I use a segue from AccountsViewController to direct me to the AccountInfoViewController (shown below) which has two textFields, one for the name and one for the balance of the account. When the latter is about to disappear a new Account is inserted in the context with the name and balance derived from the textFields. Once the parent controller appears (AccountsViewController) it tries to save the changes and updates the tableView.
Now, if I insert a new Account for which the balance is an integer number life is good; the context is able to save the changes, tableView updates its rows by showing the newly inserted account, and I am happy. When I try to insert an Account for which the balance is a decimal number, the app crashes at the point where the context tries to save the changes. I get no useful error at all as to why it happens. Here is the code for the controller managing the textFields:
class AccountInfoViewController: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var balanceField: UITextField!
var store: DataStore! // set by the parent viewController everytime this controller appears
let numberFormatter = MyFormatter()
// insert the new account into the context before the controller disappears
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
store.insertAccount(nameField.text!, balance: numberFormatter.numberFromString(balanceField.text!)!)
}
}
The MyFormatter is this:
func MyFormatter() -> NSNumberFormatter {
let formatter = NSNumberFormatter()
formatter.numberStyle = .DecimalStyle
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
return formatter
}
and the DataStore shown above contains a simple Core Data Stack and is responsible for inserting into the context:
// DataStore.swift
class DataStore {
let coreDataStack = CoreDataStack(modelName: "SmartMoney")
// inserts a new account into the context
func insertAccount(name: String, balance: NSNumber) -> Account {
let account = NSEntityDescription.insertNewObjectForEntityForName("Account",
inManagedObjectContext: coreDataStack.mainQueueContext) as! Account
account.name = name
account.initBalance = balance
return account
}
}
Is there any reason why the context fails to save the changes when the balanceField contains a non-integer number? Thank you for reading and please let me know if you would like me to post any other parts of the code.
I was finally able to figure out what's going on. Changing my attribute name from initBalance to startingBalance makes everything work again. In fact, changing the attribute's name to anything that does not start with new or init works just fine. I got the idea from this post.
It seems that when using ARC, your property's name should not start with the word new. It turns out that initBalance (or newBalance for that matter) produces the same issue. Hope it helps the next poor soul running in a similar problem.

How to create an NSDictionary and Write and Read the information from a NSUserDefaults object in swift

I want to store 3 variables all of type Int for a game (gameLevel,time,clicks). I want to save the values of these variables in one UIViewController at the end of the game, and pass it to another UIViewController that will present the gameScore (using UILabel).
Should I use an NSDictionary object for this task? and how do I create an NSUserDefaults object and pass it the NSDictionary?
Save the values in NSUserDefaults when game ends
NSUserDefaults.standardUserDefaults().setInteger(gameLevel, forKey: "gameLevelKey")
NSUserDefaults.standardUserDefaults().setInteger(time, forKey: "timeKey")
NSUserDefaults.standardUserDefaults().setInteger(clicks, forKey: "clicksKey")
NSUserDefaults.standardUserDefaults().synchronize()
Get the saved values from NSUserDefaults in other view controller
let gameLevel = NSUserDefaults.standardUserDefaults().integerForKey("gameLevelKey")
let time = NSUserDefaults.standardUserDefaults().integerForKey("timeKey")
let clicks = NSUserDefaults.standardUserDefaults().integerForKey("clicksKey")
NSUserDefaults is like database where you can save values using setXXX method and retrieve values using the xxxForKey method

fatal error: unexpectedly found nil while unwrapping an Optional value - UITableView Add Button

I am trying to add names into a UITableView. The names will be stored as a NSUserDefault.
My viewDidLoad:
var PlayersUserDefault = NSUserDefaults.standardUserDefaults()
if (PlayersUserDefault.arrayForKey("playersKey") != nil){
players = PlayersUserDefault.arrayForKey("playersKey")
}
Add name button:
#IBAction func addButtonAction(sender: AnyObject) {
players!.append(namesTextBox.text)
myTableView.reloadData()
}
When I press the addButtonAction, I am getting error on following:
players!.append(namesTextBox.text)
Players declaration:
var players = NSUserDefaults().arrayForKey("playersKey")
Any idea why I am getting error?
Error image:
In one line you use NSUserDefaults.standardUserDefaults() and in the other you create new instance of NSUserDefaults and ask for "playersKey". What you should do is to use NSUserDefaults.standardUserDefaults() for retrieving AND saving your players.
Take a look at the refence:
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/#//apple_ref/doc/constant_group/NSUserDefaults_Domains
For init:
This method does not put anything in the search list. Invoke it only
if you’ve allocated your own NSUserDefaults instance instead of using
the shared one.
and for shared instance:
If the shared defaults object does not exist yet, it is created with a
search list containing the names of the following domains, in this
order:
NSArgumentDomain, consisting of defaults parsed from the application’s
arguments
A domain identified by the application’s bundle identifier
NSGlobalDomain, consisting of defaults meant to be seen by all
applications
Separate domains for each of the user’s preferred languages
NSRegistrationDomain, a set of temporary defaults whose values can be
set by the application to ensure that searches will always be
successful
The defaults are initialized for the current user. Subsequent
modifications to the standard search list remain in effect even when
this method is invoked again—the search list is guaranteed to be
standard only the first time this method is invoked.
The players array is nil at the point of time thats why the array is not unwrapped. If you tap the button at the first time, your UserDefaults will not be having players, So the players array is nil. So you can solve this in two ways do like this.
On your viewDidLoad()
var PlayersUserDefault = NSUserDefaults.standardUserDefaults()
if (PlayersUserDefault.arrayForKey("playersKey") != nil){
players = PlayersUserDefault.arrayForKey("playersKey")
}else {
players = [String]()
}
Otherwise, initialise the players array with an empty string array like this:
var players = [String]()
This may help you.
You could try unwrapping the value of players before attempting to do append. Then you will know for sure if it's nil or not.
Try:
#IBAction func addButtonAction(sender: AnyObject) {
if let playerValue = players {
players!.append(namesTextBox.text)
myTableView.reloadData()
}else{
println("players is nil!")
}
}

Resources