Resave NSUserDefaults value for selected key for index.row - arrays

I have array NSUserDefaults type :
let userValue = ["name": self.nameLbl.text ?? "", "lastName": self.lastNameLbl.text ?? "", "city": cityLbl.text ?? ""] as! [String : String]
var userArray = UserDefaults.standard.array(forKey: "userInfo") as? [[String: String]] ?? []
UserDefaults.standard.set(userArray, forKey: "userInfo")
And save this array in first `ViewController`
In second ViewController Im display this array in UITAbleView
class ...
var userInfo = [[String:String]]()
override func viewDidLoad() {
super.viewDidLoad()
userInfo = UserDefaults.standard.array(forKey: "userInfo") as? [[String: String]] ?? []
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UserTableViewCell
var userItem = userInfo[indexPath.row]
cell.nameLbl?.text = item["name"]
cell.lastNameLbl.text = item["lastName"]
cell.cityLbl.text = item["city"]
and under UITAbleView I have 3 UIextField's and UIButton for the opportunity to change user information
When user pass text in UIextField's I want to resave value for key
How can I remove selected name and save new name to correctly user??
To Abhirajsinh Thakore answer :
Im update code in cellForRowAt
var userItem = userInfo[indexPath.row]
cell.nameLbl?.text = item["name"]
cell.lastNameLbl.text = item["lastName"]
cell.cityLbl.text = item["city"]
item["name"] = cell.nameLbl?.text
var maArray = UserDefaults.standard.array(forKey: "userInfo") as? [[String: String]] ?? []
item.updateValue(cell.nameLbl?.text, forKey: "name")
maArray.append(item)
But its not save

You can fetch your complete array from Userdefaults
Now do is that get the new values from textField and replace that at the specific indexPath.row
For e.g:
var userInfo = [[String:String]]()
let data = userInfo[indexPath.row]
data["name"] = txtName.text
data["address"] = txtAddress.text
And now store this full array back to userDefaults and you will get the updated Result every Time.
Hope this helps.
Edit with reference to the code
Do like this:
var maArray = UserDefaults.standard.array(forKey: "userInfo") as? [[String: String]] ?? []
let innerData = maArray[indexPath.row]
innerData["name"] = cell.nameLbl?.text
innerData["lastName"] = cell.lastNameLbl.text
innerData["city"] = cell.cityLbl.text
// And save the maArray back to userDefaults

Related

Search bar in Table view sends wrong data to another Table View

I have one tableview containing data that is fed from an Array with 14 entries. I have added a search bar where I can filter this data and this works fine, but when I try to send the filtered data to a second table view, the data that is sent is the count of my filtered data. So if I search something starting with G(13th and 14th place in my array), that brings back two results which is fine but when I choose the first entry off my filtered data(the two results), the data that is passed to the second Table View is the [0] entry(A) of my initial TVC and not the 13th(G12).So depending on the filtered data I always get the first few entries of my initial array.
struct ImageForManuf {
let image: UIImage
let name: String
init(nameInit: String) {
self.name = nameInit
image = UIImage(named: nameInit)!
}
}
struct SecondTable {
var secondTitle : [String]
var pic : [UIImage?]
}
//for search bar
#IBOutlet weak var searchBar: UISearchBar!
var filteredData: [ImageForManuf]!
var searching = false
var firstArray = [ImageForManuf]()
//we are adding elements on the SecondTable structure
var secondArray = [SecondTable]()
override func viewDidLoad() {
super.viewDidLoad()
//for search bar
searchBar.delegate = self
filteredData = firstArray
firstArray = [ "A","A2","B3","B4","B5","C6","C7","D8","E9","F10","F11","G12","G13","H14",
].map(ImageForManuf.init(nameInit:))
filteredData = firstArray
secondArray = [SecondTable(secondTitle: ["A1"],
pic: [UIImage(named: "A1")]),
SecondTable(secondTitle: ["B1","B2","B3"],
pic: [UIImage(named: "B1"),UIImage(named: "B2"),UIImage(named: "B3")]),
SecondTable(secondTitle: ["C1","C2"],
pic: [UIImage(named: "C1"),pic: [UIImage(named: "C2")]),
SecondTable(secondTitle: ["D1"],
pic: [UIImage(named: "D1"),
SecondTable(secondTitle: ["E1"],
pic: [UIImage(named: "E1"),
SecondTable(secondTitle: ["F1","F2"],
pic: [UIImage(named: "F1"),pic: [UIImage(named: "F2")]),
SecondTable(secondTitle: ["G1","G2"],
pic: [UIImage(named: "G1"),pic: [UIImage(named: "G2")]),
SecondTable(secondTitle: ["H1"],
pic: [UIImage(named: "H1")
]
This is my TV configuration
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if searching
{
return filteredData.count
}else{
return firstArray.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let Cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableTableViewCell
Cell.textLabel?.textColor = .systemBlue
Cell.textLabel?.font = .boldSystemFont(ofSize: 20)
if searching
{
Cell.textLabel?.text = filteredData[indexPath.row].name
Cell.imageManuf?.image = filteredData[indexPath.row].image
}else{
Cell.textLabel?.text = firstArray[indexPath.row].name
Cell.imageManuf?.image = filteredData[indexPath.row].image
}
return Cell
}
//we need to create a variable that can hold the destination view controller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if searching {
let row = self.tableView?.indexPathForSelectedRow?.row ?? 0
let destViewController = segue.destination as! SecondTableViewController var secondTableArray : SecondTable
secondTableArray = secondArray[row]
destViewController.secondTableVcArray = secondTableArray.secondTitle
destViewController.detailVcArray = thirdArray[row]
}else{
let row = self.tableView?.indexPathForSelectedRow?.row ?? 0
let destViewController = segue.destination as! SecondTableViewController
var secondTableArray : SecondTable
secondTableArray = secondArray[row]
secondTableArray created in SecondTableViewController
destViewController.secondTableVcArray = secondTableArray.secondTitle
destViewController.detailVcArray = thirdArray[row]
}
}
Lastly this is my searchBar configuration
//Mark: Search Bar config
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredData = firstArray.filter({$0.name.lowercased().prefix(searchText.count) == searchText.lowercased()})
searching = true
//to reload the data
self.tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
tableView.reloadData()
}
This is the second TVC:
class SecondTableViewController: UITableViewController {
//we are loading the secondArray via the secondTableVcArray
var secondTableVcArray = [String]()
//we are loading the thirdArray via the detailVcArray
var detailVcArray : [DetailView]?
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return secondTableVcArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "secondCell", for: indexPath) as! SecondTableViewCell
cell.textLabel?.textColor = .white
cell.textLabel?.font = .boldSystemFont(ofSize: 20)
//we load the data of the secondTableVcArray to our cell
cell.textLabel?.text = secondTableVcArray[indexPath.row]
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let row = self.tableView?.indexPathForSelectedRow?.row else {
print("Error: problem with second table view or selection")
return
}
guard let dest = segue.destination as? DetailsViewController else {
print("Error: couldn't find expected DetailsViewController")
return
}
guard let details = detailVcArray else {
print("Error: data not set for SecondTableViewController")
return
}
dest.displayDetail = details[row]
}
}
Can somebody help with the row element of my prepareforSeque method and advice the syntax on how to get the indexPath of my firstArray as #vadian suggested? The second condition works fine(not searching) but I don't seem to be able to pull the right item from my DataSource in the searching condition.

Unable to add Tableview cell value to JSON Parameter, coming nil why? in swift

I am adding tableview cell label text to phNumArray, in tableview i am getting all values but when i try to pass in service call then its coming nill why?
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var joinersTableView: UITableView!
var tablcellArray = [String]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: Namescell = tableView.dequeueReusableCell(withIdentifier: "Namescell") as! Namescell
cell.empRoleLbl.text = empTeftfield.text
tablcellArray.append((cell.empRoleLbl.text!))
print("employee names array \(tablcellArray)")// here coming all appende values
return cell
}
func getPostData(params: [String:Any]) -> Data? {
return try? JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
DispatchQueue.main.async {
self.joinersTableView.reloadData()
}
}
func callPostApi() {
print("tableview emp values\(tablcellArray)")// here array values not coming
let url = URL(string: "http://itaag-env-1/")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
print("appende values \(tablcellArray)")
try? request.setMultipartFormData(["contactsList": "\(tablcellArray)"], encoding: .utf8)
DispatchQueue.main.async {
self.joinersTableView.reloadData()
}
URLSession.shared.dataTask(with: request) { data, _, _ in
if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
}
}.resume()
}
}
in tableview cellfor row appended values coming.. but when i try to bring that array in callPostApi func then tablcellArray showing nil why?
please share your knowledge, please try to solve this error.
firstly change
var tablcellArray = [String]()
to
var tablcellArray = [String]
then in your cellForRowAt try to access your data such as
let empTeftfield = tablcellArray[indexPath.row]
if this line prints correctly
cell.empRoleLbl.text = empTeftfield.text
this should work.
if not prints your value reload tableview after fetching data from api. you shouldnt add values to your array in your conditions.

NSUserDefaults check if value exist for key

I have UICollectionView contains: UIlabel and UIButton (text in labels comes from API)
when I press UIButton text from UIlabel and CostLbl stored in UserDefaults.standard.array(forKey: "car")
let imageData = UIImageJPEGRepresentation(image.image!, 1.0) as NSData?
let newValues = ["name": self.nameLbl.text ?? "", "price": self.costLbl.text ?? "", "image": imageData]
var mArray = UserDefaults.standard.array(forKey: "car") as? [[String: Any]]
maAr?.append(newValues)
Question : when UIButton is press need to check if text from UIlabel is in array(forKey: "car") , if not - can to stored for key,, and if text already in array(forKey: "car") cant add to array
I wrote as vadian suggested
var maAr = UserDefaults.standard.array(forKey: "car") as? [[String: Any]] ?? []
if !maAr.contains(where: newValues) {
maAr.append(newValues)
def.set(maAr, forKey: "car")
}
but catch error to (where: newValues) -
Cannot convert value of type '[String : Any]' to expected argument type '([String : Any]) throws -> Bool'
How can this be changed?
First of all declare the dictionary as [String:String] in this case there is no type cast and no annotation.
let newValues = ["name": nameLbl.text ?? "", "price": costLbl.text ?? ""]
Read the array, check if the array contains the value, if NO append the item and save the array back, if YES do nothing
var carArray = UserDefaults.standard.array(forKey: "car") as? [[String: String]] ?? []
if !carArray.contains(newValues) {
carArray.append(newValues)
UserDefaults.standard.set(carArray, forKey: "car")
}

How to conform an array from another array that comes from a REST Service?

I’m trying to create a TableView with elements that comes from a REST Service, It’s a list of coupons that has description, title, category and images. So I deserialize the data first, put it in an array and then convert it into an specific array per each section, but my loop is not working, can anyone help me please?
This is my code:
var couponsTitle : [String] = []
var couponsDesc : [String] = []
var couponsCat : [String] = []
func getCoupons(){
let miURL = URL(string: RequestConstants.requestUrlBase)
let request = NSMutableURLRequest(url: miURL!)
request.httpMethod = "GET"
if let data = try? Data(contentsOf: miURL! as URL) {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary
let parseJSON = json
let object = parseJSON?["object"] as! NSDictionary
let mainCoupon = object["mainCoupon"] as! NSArray
let coupons = object["coupons"] as! NSArray
for i in mainCoupon {
self.couponsCat.append((mainCoupon[i as! Int] as AnyObject).value(forKey: "category"))
}
for i in coupons {
self.couponsCat.append((coupons[i as! Int] as AnyObject).value(forKey: "category"))
}
for i in mainCoupon {
self.couponsDesc.append((mainCoupon[i as! Int] as AnyObject).value(forKey: “description"))
}
for i in coupons {
self.couponsDesc.append((coupons[i as! Int] as AnyObject).value(forKey: “description"))
}
for i in mainCoupon {
self.couponsTitle.append((mainCoupon[i as! Int] as AnyObject).value(forKey: “name"))
}
for i in coupons {
self.couponsTitle.append((coupons[i as! Int] as AnyObject).value(forKey: “name"))
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeTableViewCell
cell.couponTitle.text = couponsTitle[indexPath.row]
cell.couponDescription.text = couponsDesc[indexPath.row].
cell.couponCategory.text = couponsCat[indexPath.row]
return cell
}
My biggest issue is that I don’t know how to put in a loop the array but with the specification of each section (I mean, the title, description, category, etc.) Any idea?
Rather than having three arrays (one for each property), why not have a custom class for Coupon that has three properties?
class Coupon: AnyObject {
var description: String
var title: String
var category: String
init(description: String, title: String, category: String) {
self.description = description
self.title = title
self.category = category
}
}
If you do it that way, you can avoid so many loops by doing something like this
for coupon in mainCoupon {
let description = mainCoupon["description"]
let title = mainCoupon["name"]
let category = mainCoupon["category"]
let newCoupon = Coupon(description: description, title: title, category: category)
couponsArray.append(newCoupon)
}

How to use NSUserDefaults to store an array of dictionaries

Trying to store an array of dictionaries with NSUserDefaults.
var theTasks: [[String:Any]] = [["num":1,"title":"example","colour":"red"]]
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(theTasks, forKey: "myTasks")
defaults.synchronize()
let selected = theTasks[1]
Gives error:
Cannot convert value of type '[[String:Any]]' to expected argument of type 'AnyObject?'
Swift 3.x
In Swift 3 it has changed so now it needs to be saved as [Any] Any Array and use UserDefaults array(forKey:) method to load it:
let theTasks: [Any] = [["num": 1, "title": "example", "colour": "red"]]
UserDefaults.standard.set(theTasks, forKey: "myTasks")
if let loadedTasks = UserDefaults.standard.array(forKey: "myTasks") as? [[String: Any]] {
print(loadedTasks)
}
var theTasks: [[String: Any]] {
get {
return UserDefaults.standard.array(forKey: "myTasks") as? [[String: Any]] ?? []
}
set {
UserDefaults.standard.set(newValue as [Any], forKey: "myTasks")
}
}
Swift 2.x
You just need to save it as a AnyObject array and use NSUserDefaults method arrayForKey to load it:
let theTasks: [AnyObject] = [["num": 1, "title": "example", "colour": "red"]]
NSUserDefaults.standardUserDefaults().setObject(theTasks, forKey: "myTasks")
if let loadedTasks = NSUserDefaults.standardUserDefaults().arrayForKey("myTasks") as? [[String: AnyObject]] {
print(loadedTasks)
}
You can also create a computed property with a getter and a setter to do all the work behind the scenes for you as follow:
var theTasks: [[String: AnyObject]] {
get {
return NSUserDefaults.standardUserDefaults().arrayForKey("myTasks") as? [[String: AnyObject]] ?? []
}
set {
NSUserDefaults.standardUserDefaults().setObject(newValue as [AnyObject], forKey: "myTasks")
}
}
print(theTasks) // [["title": example, "colour": red, "num": 1]]
theTasks[0]["title"] = "another example"
print(theTasks) // [["title": another example, "colour": red, "num": 1]]
Just call the .setObject() method directly from NSUserDefaults()and it should work fine.
NSUserDefaults().setObject(theTasks, forKey: "myTasks")

Resources