I am developing an app that has a textView in FirstViewController and a tableView in the SecondViewController. In the app user types in a string using a textView, which is then turned into an array with the press of a button (indicated by an IBAction buttonIsPressed) and transferred onto a tableView in the next view controller with the help of UserDefaults. Right now, I want the code to be able to append all of the strings into one array every time user types in a string in textView. I have tried every single method I found on the internet to append either strings or arrays into one array but none of them worked. I would really appreciate if some of you can help me out. Here is the code:
#IBAction func buttonIsPressed(_ sender: Any) {
var newitems = textField.text!.components(separatedBy: CharacterSet(charactersIn: ", []()\n.:"))
print(newitems)
if newitems.contains(""){
newitems.removeAll { $0 == ""}
UserDefaults.standard.set(newitems, forKey: "items")
print(newitems)
}else{
let newitems = textField.text!.components(separatedBy: CharacterSet(charactersIn: ", []()\n.:"))
UserDefaults.standard.set(newitems, forKey: "items")
}
textField.text = ""
}
First: you shouldn't use userdefaults for temporary storage
UserDefaults.standard.set(newitems, forKey: "items")
unless you save them for next launch
Second: create an array inside the source vc like
var arr = [String]()
and append to it the latest content
arr += newitems
then pass arr to the destination vc
Related
Might be an easy question for the experts but as a newbie I'm struggling to figure this out and confusing myself so I thought I would just post it here. What I would like to do is create a nested array when this Add button is pressed. I would like to build a list of "selections" to store in UserDefaults under each "id". I've simplified the code but I already have "id" and "selection" being called in from elsewhere, so those variables are working, I just need to know how to add the selection to list of selections under the id. I hope this makes sense. 1 id, list of many selections.
Code below that I've been working with, found through this tutorial
#State var id = ""
#State var selection = ""
let userDefaults = UserDefaults.standard
Button(action: {
userDefaults.set(dictionary, forKey: "myKey")
var strings: [String:String] = userDefaults.object(forKey: "myKey") as? [String:String] ?? [:]
strings[id] = selection
userDefaults.set(strings, forKey: "myKey")
}) {
Text("Add")
}
I have an UICollectionView inside UITableViewCell and I'm using UserDefaults to save an array of the selected item in didSelectItem function to keep selected state after dismissing the parent view controller of them:
var arrSelectedIndex = [IndexPath]()
let encodedData = NSKeyedArchiver.archivedData(withRootObject: arrSelectedIndex)
UserDefaults.standard.set(encodedData, forKey: "arrayOfSelectedItem")
UserDefaults.standard.synchronize()
And whenever I show up the view controller I set my array with UserDefaults again in awakeFromNib:
arrSelectedIndex = UserDefaults.standard.array(forKey: "arrayOfSelectedItem") as? [IndexPath] ?? [IndexPath]()
But both my array and the UserDefaults return 0 elements (I tried to print out value of arrSelectedIndex and UserDefaults.standard.array(forKey: "arrayOfSelectedItem") as? [IndexPath] ?? [IndexPath]()) and both of them is 0 even if they have data when selected item. Does awakeFromNib reset all things inside it?
The problem is this line:
UserDefaults.standard.array(forKey: "arrayOfSelectedItem") as? [IndexPath]
That will fail, because what you saved under that key is not an array. Here is what you said earlier:
let encodedData = NSKeyedArchiver.archivedData(withRootObject: arrSelectedIndex)
UserDefaults.standard.set(encodedData, forKey: "arrayOfSelectedItem")
What you saved is encodedData. It is not an array. It is a Data. The array is encoded inside it.
First thing is to save the list in userDefault it not necessary to archive it, You can if contains basic data types.
Second, If you archive the list before saving it to UserDefault, Then You have to unarchive the encoded data to get the list.
Here is the method,
data = UserDefaults.standard.data(forKey: "arrayOfSelectedItem") as? Data
arrSelectedIndex = NSKeyedUnarchiver.unarchiveObject(with: data) as? [IndexPath] ?? [IndexPath]()
Hope this will help.
Thank you all. I have tried to unarchive before setting it to my array again and it's worked.
I tried to solve this problem for a couple of days before submitting the app, so here it goes. I am developing an app that uses UserDefaults to save a string from a different view controller with a press of a button and to transfer it a table view in the next view controller. However, for some unknown reason, the app works perfectly on iPhone X (and iPhone XR), but it does not save the string and react to a press of a button whenever I run the app on a different iPhone model. Here is my code:
//FirstViewController
#IBAction func buttonIsPressed(_ sender: Any) {
if var items = UserDefaults.standard.object(forKey: "items") as? [String]{
var newitems = textField.text!.components(separatedBy: CharacterSet(charactersIn: ", []()\n.:"))
print(items)
if newitems.contains(""){
newitems.removeAll { $0 == ""}
items.append(contentsOf: newitems)
UserDefaults.standard.set(items, forKey: "items")
}else{
let newitems = textField.text!.components(separatedBy: CharacterSet(charactersIn: ", []()\n.:"))
UserDefaults.standard.set(newitems, forKey: "items")
}
textField.text = ""
}
}
//SecondViewController
var scannedText: String = "Detected text can be edited here." {
didSet {
textView.text = scannedText
let str = scannedText.uppercased()
let allergens = UserDefaults.standard.array(forKey: "items") as! [String]
let string = str.components(separatedBy: CharacterSet(charactersIn: ", []()\n.:"))
print(string)
for allergen in allergens{
if string.contains(String(Substring(allergen))) == true {
print("I found the string \(allergen)")
allegenLabel.text = "Not safe"
allegenLabel.alpha = 1 //Make the label visible
allegenLabel.textColor = .red
// let attributedString = allergen.highlight([allergen], this: .red)
// textView.attributedText = attributedString
allergensFound.append(allergen)
print(allergensFound)
}
if string.contains(String(Substring(allergen))) == false {
allegenLabel.text = "Safe"
allegenLabel.alpha = 1 //Make the label visible
allegenLabel.textColor = UIColor.colorGreen
// table.reloadData()
}
}
}
}
Please ask me if you need further description in the code. Thanks!
Edit: To be more exact I am creating a code that will find a string in the array of strings that will then notify the user with AllegenLabel.text. The whole app is divided into different view controllers. The user inputs in a string using a text field in FirstViewController and then that string has to be found in a different array of strings in SecondViewController. For some reason UserDefaults successfully stores and retrieves the string on my phone but does not work on different devices. For example, whenever I click the save button in FirstViewController, a string has to be stored and shown in the console, but for some unknown reason it does not work. Sorry if I was unclear
I think you can try:
UserDefaults.standard.synchronize()
maybe...
I am tracking a user's preferences in my iOS app using UserDefaults -- when a user selects a table cell, it adds the cell's text to my key. That part works.
Now, I want to allow the user to remove the matching key value from the key when a row is selected. If a cell says "Episode 1", it should remove the value from UserDefaults.
From the documentation, there's an instance method for removeObject. Here's what I wrote:
let defaults = UserDefaults.standard
var myarray = defaults.stringArray(forKey: "SavedStringArray") ?? [String]()
if let datastring = TableData[indexPath.row] as? String {
if !myarray.contains(datastring) {
myarray.append(datastring)
defaults.removeObject(myarray, forKey: "SavedStringArray")
defaults.synchronize()
}
This returns an error for Extra argument in call -- I assume it means myarray, but if I can't add that argument, how can I tell it to remove only one value (stored in myarray)?
If I print the UserDefaults.standard, it will return a list of stored episode values like `["First Episode", "Second Episode", "Third Episode"]
Any idea how I can remove Third Episode when that cell is clicked here?
I have following code which will work for you.
if myarray.contains(datastring) {
myarray.remove(at: myarray.index(of: datastring)!)
} else {
myarray.append(datastring)
}
defaults.set(myarray, forKey: "SavedStringArray")
This code will remove element from array and set array again in User defaults for same key, So it will replace you array with new array.
You can add if string is not present or remove the string if it is present. And then update the array.
Then set that array for the key.
if !myarray.contains(datastring) {
myarray.append(datastring)
} else {
myarray = myarray.filter{$0 != datastring}
}
defaults.set(myarray, forKey: "SavedStringArray")
You can try This logic for array of type String i.e. [String]
var arrStr:[String] = ["Cat","Rat","Mouse"]
print(arrStr)
let datastring = "Rat"
if !arrStr.contains(datastring) {
arrStr.append(datastring)
} else {
arrStr.remove(at: arrStr.index(of: datastring)!)
}
print(arrStr)
UserDefaults.standard.set(arrStr, forKey: "SavedStringArray")
UserDefaults.standard.synchronize()
I'm developing an app when I'm trying to find users by retrieving them nickname from Firebase Database during search in a search bar. I want put all my users in an array at first but I can't.
Edit with the code working :
var userTab = [String]()
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
ref.child("users").queryOrdered(byChild: "pseudo").observeSingleEvent(of: .value, with: { (snapshot) in
if (snapshot.value is NSNull) {
print("Aucune donnée trouvée dans la base de données")
} else {
for child in snapshot.children {
let userSnap = child as! DataSnapshot
let uid = userSnap.key
let userDict = userSnap.value as! [String: AnyObject]
let pseudo = userDict["nickname"] as! String
let total = snapshot.childrenCount
print(pseudo)
self.userTab.append(pseudo) // I change this line self.userTab = [pseudo]
self.resultsController.tableView.reloadData() // I add this line
print(self.userTab)
continue // I add this line too
}
}
})
print("userTab: \(self.userTab)") // Now the array isn't empty
}
In the For Loop I can access the variable "pseudo" and print all users nicknames in the console, but outside the For Loop I can't put the pseudo variable in the array userTab. How can I do that? I really need to fill my userTab with the nickname of users and show all in a TableView then.
I already try to declare the "pseudo" variable outside the viewDidLoad() method but same issue, the array is always empty after the For Loop. What I did wrong?
See my edit, now all the users nickname are in the userTab array and I can search for them in the search bar and display the result in the tableView.
observeSingleEvent is async, it is not outside loop but in different time,
try to set breakpoints to see where it stops first
you set self.userTab = [pseudo] so now just reload tableview