I am manually entering data into a struct. However the struct is not saving the data. I tried to use userdefaults but it's not working. I want the data to appear on the label benCarson at all times if it's in the struct bad.
ViewController 1
struct bad {
static var mm = [String]()
}
ViewController 2
class ViewController2: UIViewController {
#IBOutlet var benCarson: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
benCarson.text = ViewController.bad.mm.map { " \($0)" }.joined(separator:"\n")
}
}
I think no need for struct just use the UserDefaults and it will work
For Save
let mm = ["adsa", "safds", "twer", "qwer", "dfas"]
let defaults = UserDefaults.standard
defaults.set(mm, forKey: "SavedStringArray")
defaults.synchronize()
For Retrieve
let defaults = UserDefaults.standard
let myarray = defaults.stringArray(forKey: "SavedStringArray") ?? [String]()
benCarson.text = myarray.map { " \($0)" }.joined(separator:"\n")
Related
I'm trying to create a leaderboard, but the player names and scores are not permanently saved, the "leaderboard" only contains the data from the most recent game in its text view. I tried making arrayOfData initially hold playerName and finalScore instead of being an empty array, but the problem still remains. How can I display playerName and playerScore in the leaderboard permanently and hove more names and scores added as more people play?
var finalScore = Int()
var playerName = String()
var allMyStoredData = UserDefaults.standard
var arrayOfData: [Any] = []
class secondVC: UIViewController {
#IBOutlet weak var scoreLabel: UILabel!
#IBOutlet weak var nameTF: UITextField!
#IBOutlet weak var doneButton: UIButton!
var playerScore = 0
var arrayOfData: [Any] = []
override func viewDidLoad() {
super.viewDidLoad()
scoreLabel.text = "Your score is: \(finalScore)"
loadData()
}
#IBAction func donePressed(_ sender: Any) {
saveData()
performSegue(withIdentifier: "toLeaderboard", sender: self)
}
func saveData () {
playerName = nameTF.text!
playerScore = finalScore
arrayOfData.append(playerName)
arrayOfData.append(playerScore)
allMyStoredData.set(playerName, forKey: "saveTheName")
allMyStoredData.set(playerScore, forKey: "saveTheScore")
allMyStoredData.set(arrayOfData, forKey: "saveTheArray")
}
func loadData () {
if let loadPlayerName:String = UserDefaults.standard.value(forKey: "saveTheName") as? String {
playerName = loadPlayerName
}
if let loadTheScore:Int = UserDefaults.standard.value(forKey: "saveTheName") as? Int {
playerScore = loadTheScore
}
}
}
//this is the code in the leaderboard's view controller
class leaderboardViewController: UIViewController {
#IBOutlet weak var theTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
theTextView.text = "\((arrayOfData).map{"\($0)"}.joined(separator: " Score: "))"
}
}
You are overwriting your saveTheArray item UserDefaults each time with a new array.
You want to fetch the saved array first, append the new game data, then re-save as so:
//Create user defaults instance
let userDefaults = UserDefaults.standard
//User defaults key
let historicalGameDataKey = "historicalGameData"
//Fetch game data array
var historicalGameData = userDefaults.array(forKey: historicalGameDataKey)
//Create array if it is nil (i.e. very first game)
if historicalGameData == nil {
historicalGameData = []
}
//Create game data dictionary
let gameData = [
"playerName": playerName,
"playerScore": playerScore
]
//Append game data dictionary to the array
historicalGameData?.append(["playerName": gameData])
//Save the updated array
userDefaults.set(historicalGameData, forKey: historicalGameDataKey
Core Data would be a better way to store this data, but this example should solve your problem using UserDefaults.
I have a tableview that presents events that a user creates. When you click on one of them it takes you to a different page that presents the details of the event.
I'm using Firebase and passing the postID from the tableview to the detailed view and all the information is being passed correctly in an NSDictionary.
However, when I try to access the NSDictionary out of the viewDidLoad and in an IBAction it tells me that the NSDictionary is nil. When I check in the viewDidLoad it is not nil.
I'm very new to programming and learning along the way but I've been stuck on this for a while now and have no idea whats wrong or how I can fix it
this is my code
import UIKit
import Firebase
class BeehiveViewViewController: UIViewController {
#IBOutlet weak var eventImage: UIImageView!
#IBOutlet weak var eventName: UILabel!
#IBOutlet weak var location: UILabel!
#IBOutlet weak var eventDate: UILabel!
#IBOutlet weak var eventHost: UILabel!
#IBOutlet weak var members: UILabel!
#IBOutlet weak var joinButton: roundButton!
var beehiveID: NSDictionary?
var ref = Database.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
view.setGradientBackground(colourOne: primaryColor, colourTwo: secondaryColor)
let uid = Auth.auth().currentUser?.uid
ref.child("users").child(uid!).child(self.beehiveID?["pid"] as! String).observe(.value) { (snapshot) in
let uid = self.beehiveID!["pid"] as! String
self.beehiveID = snapshot.value as? NSDictionary
self.beehiveID?.setValue(uid, forKey: "pid")
}
let imageURL = self.beehiveID!["imageDownloadURL"] as! String
let url = URL(string: imageURL)
DispatchQueue.global(qos: .background).async {
let data = NSData(contentsOf: url!)
DispatchQueue.main.async {
self.eventImage.image = UIImage(data: data! as Data)
}
}
self.eventName.text = self.beehiveID?["eventName"] as? String
self.eventDate.text = self.beehiveID?["eventDate"] as? String
self.eventHost.text = self.beehiveID?["beehiveHost"] as? String
self.location.text = self.beehiveID?["location"] as? String
let uidd = Auth.auth().currentUser?.uid
Database.database().reference().child("users").child(uidd!).child("Posts").child(self.beehiveID?["pid"] as! String).child("Members").observe(.value) { (snapshot) in
let memberCount = snapshot.childrenCount
self.members.text = "\(memberCount)"
}
let userID = Auth.auth().currentUser?.uid
Database.database().reference().child("users").child(userID!).child("Posts").child(self.beehiveID?["pid"] as! String).observe(.value) { (snapshot) in
print(snapshot)
if (snapshot.exists()){
self.joinButton.setTitle("Remove Beehive", for: .normal)
}
else{
self.joinButton.setTitle("Join Beehive", for: .normal)
}
}
}
#IBAction func buttonPressed(_ sender: Any) {
if joinButton.titleLabel?.text == "Remove Beehive"{
let uid = Auth.auth().currentUser?.uid
let dbref = ref.child("users").child(uid!).child("Posts").child(beehiveID?["pid"] as! String)
//error is the line above that beehiveID?["pid"] is nil
dbref.removeValue()
navigationController?.popViewController(animated: true)
}
if joinButton.titleLabel?.text == "Join Beehive"{
let uid = Auth.auth().currentUser?.uid
let dbref = Database.database().reference().child("users").child(uid!).child("Posts").child("Members")
Database.database().reference().child("users").child(uid!).child("Name").observe(.value) { (nameSnapshot) in
let memberName = nameSnapshot.value as! String
let userObject = [memberName: uid]
dbref.updateChildValues(userObject as! [AnyHashable : String])
}
}
}
}
I assume that you're passing beeHive's value from the previous controller as you haven't initialised or got the values of it anywhere:-
Try having a breakpoint right before the end of viewDidLoad to double-check if the dictionary isn't nil at the block
self.beehiveID = snapshot.value as? NSDictionary
Try using a check to see if the snapshot's value is nil using 'if let' or 'guard' as you could possibly just be assigning a nil value to the NSDictionary. Also, since you're using optionals for assigning each value, it doesn't return an exception but just keeps assigning the nil value to every property
Do try this and let me know. Glad to help!
I have an error when loading secondViewController with a textField and an action button so the user can fill it with some number and get it saved to UserDefaults
The idea is to be able to come back to secondVC and that the TextField shows there with the same value that input originally by the User
class MainViewController: UIViewController {
#IBOutlet weak var A3TextField: UITextField!
#IBAction func calc(_ sender: Any) {
let A3 = Cell(name: "A3", sheet: "", value: Double(A3TextField.text!)!)
print(A3)
Cell.saveCellsUserDefaults(cells: [A3], forKey: "main")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
class SecondViewController: UIViewController {
#IBOutlet weak var B3TextField: UITextField!
#IBAction func calc2(_ sender: Any) {
let B3 = Cell(name: "B3", sheet: "", value: Double(B3TextField.text!)!)
print(B3)
// persist
Cell.saveCellsUserDefaults(cells: [B3], forKey: "second")
}
override func viewDidLoad() {
super.viewDidLoad()
// retrieve from persists and draw in TextField
let cellB3FromUD = Cell.getCellsUserDefaults(forKey: "second")
print("---> cellB3FromUD \(cellB3FromUD[0].value)")
B3TextField.text = "\(cellB3FromUD[0].value)"
}
}
struct Cell: Codable {
var name: String = ""
var sheet: String = ""
var value: Double = 0
init(name: String, sheet: String, value: Double) {
self.name = name
self.sheet = sheet
self.value = value
}
static func saveCellsUserDefaults(cells: [Cell], forKey: String) {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(cells) {
let defaults = UserDefaults.standard
defaults.set(encoded, forKey: forKey)
}
}
static func getCellsUserDefaults(forKey: String)-> [Cell] {
var cells = [Cell]()
let decoder = JSONDecoder()
if let cellData = UserDefaults.standard.data(forKey: forKey) {
if let cellX = try? decoder.decode([Cell].self, from: cellData) {
cells = cellX
return cellX
}
}
return cells
}
}
I am trying to store an array in userDefaults but i am getting this error when i run my app:
'Attempt to insert non-property list object (
"Morning_Star_2.Event(title: Optional(\"test title\"), location: Optional(\"Test Location\"))"
) for key test'
Here is my code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var txtTitle: UITextField!
#IBOutlet weak var txtLocation: UITextField!
#IBOutlet weak var txtDate: UITextField!
#IBOutlet weak var txtTime: UITextField!
var eventsArray = [Event]()
#IBAction func btnSave() {
let savedEvents = UserDefaults.standard.object(forKey: "test")
let event = Event(eventTitle: txtTitle.text!, eventLocation: txtLocation.text!)
if let tempEvents = savedEvents {
eventsArray = tempEvents as! [Event]
eventsArray.append(event)
}
else {
let event = Event(eventTitle: txtTitle.text!, eventLocation: txtLocation.text!)
eventsArray.append(event)
}
UserDefaults.standard.set(eventsArray, forKey: "test")
//print(eventsArray)
}
}
To store custom objects in UserDefaults, your objects must
Inherit from NSObject
Conform to the NSCoding protocol
An example of the class implementation could look like this:
class Event: NSObject, NSCoding {
private var eventTitle: String!
private var eventLocation: String!
init(eventTitle: String, eventLocation: String) {
self.eventTitle = eventTitle
self.eventLocation = eventLocation
}
override init() {
}
required convenience init?(coder aDecoder: NSCoder) {
self.init()
eventTitle = aDecoder.decodeObject(forKey: "eventTitle") as? String
eventLocation = aDecoder.decodeObject(forKey: "eventLocation") as? String
}
func encode(with aCoder: NSCoder) {
aCoder.encode(eventTitle, forKey: "eventTitle")
aCoder.encode(eventLocation, forKey: "eventLocation")
}
}
Now, you can only store certain objects in UserDefaults. Luckily the type Data can be stored in UserDefaults. You then need to convert your array to Data, and then store it.
let data = NSKeyedArchiver.archivedData(withRootObject: eventsArray)
// This calls the encode function of your Event class
UserDefaults.standard.set(data, forKey: "test")
/* This saves the object to a buffer, but you will need to call synchronize,
before it is actually saved to UserDefaults */
UserDefaults.standard.synchronize()
When you retrieve the data it comes back as Any?, which will have to be casted to your object:
if let data = UserDefaults.standard.object(forKey: "test") as? Data {
if let storedData = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Event] {
// In here you can access your array
}
}
What is causing this to happen? the two instances of this error apear at the very bottom of my view controller in which the lines start with "userDefaults". here is my code
import UIKit
class SecondViewController : UIViewController,UITextFieldDelegate {
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var datePicker: UIDatePicker!
var aRandomDate = NSDate()
override func viewDidLoad() {
super.viewDidLoad()
datePicker.addTarget(self, action: Selector("datePickerChanged:"), forControlEvents: UIControlEvents.ValueChanged)
}
func datePickerChanged(datePicker:UIDatePicker) {
var dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = NSDateFormatterStyle.LongStyle
var strDate = dateFormatter.stringFromDate(datePicker.date)
dateLabel.text = strDate
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true;
}
#IBAction func Save(sender: UIButton) {
var t = EventSaver(pEventName: "Drinking Coffee", pEventDate: aRandomDate )
let encodedEventName = NSKeyedArchiver.archivedDataWithRootObject(t.EventName)
let encodedEventDate = NSKeyedArchiver.archivedDataWithRootObject(t.EventDate)
var encodedArray: [NSData] = [encodedEventName,]
userDefaults.setObject(encodedArray, forKey: "Event")
userDefaults.synchronize()
println("saved")
}
}
Make it like this:
#IBAction func Save(sender: UIButton) {
var t = EventSaver(pEventName: "Drinking Coffee", pEventDate: aRandomDate )
var userDefaults = NSUserDefaults.standardUserDefaults()
let encodedEventName = NSKeyedArchiver.archivedDataWithRootObject(t.EventName)
let encodedEventDate = NSKeyedArchiver.archivedDataWithRootObject(t.EventDate)
var encodedArray: [NSData] = [encodedEventName,]
userDefaults.setObject(encodedArray, forKey: "Event")
userDefaults.synchronize()
println("saved")
}
It seems like you haven't declared the constant userDefaults.
Add the following line before you set the encodedArray object in the userDefaults:
let userDefaults = NSUserDefaults.standardUserDefaults()
You aren't declaring userDefauts
let userDefaults = NSUserDefaults.standardUserDefaults()