This question already has answers here:
Attempt to insert non-property list object when trying to save a custom object in Swift 3
(6 answers)
Save custom objects into NSUserDefaults [duplicate]
(2 answers)
Closed 3 years ago.
I am not able to save the list of viewControllers in my user defaults, its getting crashed at this userDefault.set(vcList, forKey: "vcList").
The error log says:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object
import UIKit
class ViewController: UIViewController {
struct viewControllerList {
var vc1 = ViewController()
var vc2 = LoginViewController()
}
override func viewDidLoad() {
super.viewDidLoad()
let vcList = viewControllerList()
let userDefault = UserDefaults.standard
userDefault.set(vcList, forKey: "vcList")
}
}
Please help!
The UserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Boolean values, and URLs.
A default object must be a property list—that is, an instance of (or for collections, a combination of instances of) NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData.
You can try this
//MARK:- Save viewController in UserDefault
func saveInDefaults(_ viewController : UIViewController) -> Void{
do {
let encodeData = try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false)
UserDefaults.standard.set(encodeData, forKey: "vcList")
UserDefaults.standard.synchronize()
} catch {
print("error")
}
}
And Call function from viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
let vcList = viewControllerList()
self.saveInDefaults(vcList)
}
Related
I have to implement a function that loads the stored data into the shopping list array, when the app starts, and a function that stores the current contents of my list when the button is pressed. I used UserDefaults class and it works for the second function (when the button is pressed) but not for the first one (when the app starts). If I restart the app and press the button, I see that only the last input was stored. How can I fix the code if I want to store all data from the array?
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var inputEntered: UITextField!
// keyboard gives up the first responder status and goes away if return is pressed
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
inputEntered.resignFirstResponder()
return true
}
var shoppingList: [String] = []
#IBAction func buttonAddToList(_ sender: UIButton) {
if let item = inputEntered.text, item.isEmpty == false { // need to make sure we have something here
shoppingList.append(item) // store it in our data holder
}
inputEntered.text = nil // clean the textfield input
print(shoppingList.last!) // print the last element to avoid duplicates on the console
storeData()
}
// this function stores the current contents of my list when the button is pressed
func storeData () {
let defaults = UserDefaults.standard
defaults.set(inputEntered.text, forKey: "Saved array")
print(defaults)
}
// to call the function storeDate(), when the app restarts
override func viewDidLoad() {
super.viewDidLoad()
inputEntered.delegate = self
// Do any additional setup after loading the view.
storeData()
}
}
You can add a getter and a setter to your array and persist your values to user defaults. This way you don't need to call storeData and or remembering to load the data when initialising your array:
var shoppingList: [String] {
get {
UserDefaults.standard.stringArray(forKey: "shoppingList") ?? []
}
set {
UserDefaults.standard.set(newValue, forKey: "shoppingList")
}
}
You are calling storeData() in viewDidLoad, but inputEntered is empty then, so you are storing blank data.
Also, defaults.set(inputEntered.text, forKey: "Saved array") doesn't append new data onto the key -- it overwrites what is there. So you are not storing the array, you are only storing the last value.
You need to store shoppingList to store the array.
I'm unsure if I have got what you are asking for but have you tried looking into UITextFieldDelegate.
If you add this, it will ensure add the protocols of which I am sure there is a method that can be called when the user finishes editing text field.
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 5 years ago.
I know using custom delegate is an option for data traveling, but I want to know what's the best practice, also I have tried many other methods but the array in Destination ViewController always shows nil
Basically, you need to bind the data with the destination viewcontroller.
You have to pass data like this:-
let otherUserInstance = self.storyboard?.instantiateViewControllerWithIdentifier("OtherUserProfileVC") as! OtherUserProfileVC
otherUserInstance.userID = self.data["UserId"]as! String //You can use array or dictionay instead of string
self.navigationController?.pushViewController(otherUserInstance, animated: true)
class OtherUserProfileVC: UIViewController {
var userID = "" //declare as property of class
}
You may pass data by define array public like this way
var array: NSMutableArray!
class FirstViewController: UIViewController {
}
and then access it in other class like this way
class SecondViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
array = [1, 2, 3]
}
}
This question already has an answer here:
Expected Declaration Error using Swift
(1 answer)
Closed 6 years ago.
I'm writing code for a game I am making and am trying to create a User Default so that it saves data after you close the app.
let UserDefaults = NSUserDefaults.standardUserDefaults()
UserDefaults.setBool(false, forKey: "hasStarted")
But on the last line it underlines UserDefaults and says "expected declaration.
What have I done wrong?
In you are using Swift 2, then what you have to do is just putting your code inside a function/method:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setBool(false, forKey: "hasStarted")
like so, in:
func applicationWillTerminate( application: UIApplication) {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setBool(false, forKey: "hasStarted")
}
or here:
func applicationWillResignActive( application: UIApplication) {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setBool(false, forKey: "hasStarted")
}
I've called it there because you said that you want it to save it when the app is closed.
EXPLANATION:
You called your function outside any function/method's body, which is restricted in swift. You are not allowed to do anything outside methods(just in the body of the class), besides for declaring and initialising variables/constants.
Where are you declaring and intializing the variable? If you are initializing the variable outside any method then it will give you the same error you mentioned
Try another name for it.
Try this:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setBool(false, forKey: "hasStarted")
I am creating a To-Do App on IOS Platform Swift 3
I am trying to save note in UITextView so when i hit back or terminate application the data is saved.
StoryBoard Have a UITextView and a save button at the navigation bar
How to make user enter his text in UITextView and save it
class Details: UIViewController, UITextViewDelegate{
// MARK: - IB
#IBOutlet weak var noteText: UITextView!
#IBAction func addNote(_ sender: UIButton) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let addNote = Note(context: context)
addNote.details = noteText.text!
//Saving
(UIApplication.shared.delegate as! AppDelegate).saveContext()
}
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var Notes: [Note] = []
func getData() {
do {
Notes = try context.fetch(Note.fetchRequest())
} catch {
print("Fetching Failed")
}
}
override func viewWillAppear(_ animated: Bool) {
getData()
}
override func viewDidLoad() {
super.viewDidLoad()
let MyIcon = UIImageView(image: UIImage(named: "037_Pen"))
self.navigationItem.titleView = MyIcon
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Any idea how to display it ?
Created Entity called Note with Attribute details of type String
Dealing with data in iOS application
If you want to save your data inside application then you need to do something more inside your application for data saving purpose. This way you can save data inside application weather terminate application it will show your saved data and fetch again.
1.) For Short Date save can use UserDefaults
2.) By using SQLite
3.) By Using Coredata
4.) By Using Realm, For more details check Example.
You need to create database to save the text value every time as per your requirement.
You can create the database by using any one of the below :
Core dataGet tutorial from here
SQLite Get tutorial from here
Save your text data by using anyone these and then fetch the data and assign at the UI.
I am fairly new to developing in Swift, and I seem to be struggling with one of the key concepts.
I am looking to pass data between different UIViewControllers, allowing them all to access and manipulate it.
For example, in my application, I have created a simple data store class that contains and array of items. I want this array to be accessible by all ViewControllers.
I initialise the store within AppDelegate:
var itemStore = ItemStore()
I then create the first UIViewController and pass in the store so that it has access to it:
FirstViewController(itemStore: ItemStore)
So to do this I need to make changes to the init of FirstViewController so that it is able to accept itemStore as an argument.
I then want to pass that data to SecondViewController, and then to ThirdDataController.
It seems unnecessary to me that I have to edit every single UIViewController class so that it accepts the itemStore as an argument.
What are my options here? Some people have told me to store the data as a property of AppDelegate so that it is accessible by all. However, it seems that is not the right way of doing it.
Any advice?
You can pass data using a segue like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == “segueTest”) {
var svc = segue.destinationViewController as secondViewController;
svc.toPass = textField.text
}
}
another solution
class AnsViewController: UIViewController {
var theNum: Int
override func viewDidLoad() {
super.viewDidLoad()
println(theNum)
}
}
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
let viewController = self.storyboard.instantiateViewControllerWithIdentifier("ansView") as AnsViewController
viewController.num = theNum
self.presentViewController(viewController, animated: true, completion: nil)
}
complete Demo Solution with Tutorial might be helpful to you.
Tutorial
edited Added NSUserDefault Solution to Save Data
let highscore = 1000
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setValue(highscore, forKey: "highscore")
userDefaults.synchronize() // don't forget this!!!!
Then, when you want to get the best highscore the user made, you have to "read" the highscore from the dictionary like this:
if let highscore = userDefaults.valueForKey("highscore") {
// do something here when a highscore exists
}
else {
// no highscore exists
}
I hope this helps!
NSUserDefaults supports the following data types:
NSString NSNumber NSDate NSArray NSDictionary NSData
Here is the Complete Demo Code, might be helpful to you