Removing Custom Objects from List in UserDefaults - ios

I am trying to remove an element from a list which is stored in NSUserDefaults. The getAll function is implemented below:
func getAllOrders() -> [Order] {
var orders = [Order]()
if let userDefaults = UserDefaults(suiteName: "group.com.johndoe.SoupChef.Shared") {
if let ordersData = userDefaults.data(forKey: "Orders") {
orders = try! JSONDecoder().decode([Order].self, from: ordersData)
}
}
return orders
}
And here is the code for deleting the order.
func delete(order :Order) {
var persistedOrders = getAllOrders()
persistedOrders.removeAll { persistedOrder in
persistedOrder.identifier.uuidString == order.identifier.uuidString
}
}
After deleting the order in the code above when I call getAllOrders I still see all the elements, meaning I don't see the order being deleted.

That's because you don't save your changes. Once you've performed the removal you need to turn persistedOrders back into JSON and then:
userDefaults.set(json, forKey:"Orders")

You need to use jsonEncoder and encode the edited array then store it again the user defaults
func delete(order :Order) {
var persistedOrders = getAllOrders()
persistedOrders.removeAll { persistedOrder in
persistedOrder.identifier.uuidString == order.identifier.uuidString
}
do {
let data = try JSONEncoder().encode(persistedOrders)
userDefaults.set(data, forKey:"Orders")
}
catch {
print(error)
}
}

You have to store correctly your UserDefaults
UserDefaults.standard.set(json, forKey:"Orders")
Now, you can remove them using:
UserDefaults.standard.removeObject(forKey: "Orders")

Related

Deteting item in an array stored in UserDefaults

I am saving items in UserDefaults and it works fine. I simply append new elements to the array. now deleting the entire saved items is done but now I want to enable the user the ability to delete just one item instead of deleting the entire saved items.
below is how I delete all the entire array
public func deleteSavePropery() {
delete(key: propertyKey)
}
private func delete(key: String) {
storage.removeObject(forKey: key)
}
NOTE, saveProperty is a Codable object
You need to retrieve the array if exists then delete the item finally save back
let storage = UserDefaults.standard
private func deleteItem(key: String,item:Item) {
if let data = storage.data(forKey: key) , var arr = try? JSONDecoder().decode([Item].self, from: data) {
arr.removeAll(where: { $0 == item})
guard let res = try? JSONEncoder().encode(arr) else { return }
storage.set(res, forKey: key)
}
}
struct Item:Codable,Equatable {
let name:String
}
You need to,
Fetch the array from UserDefaults.
Remove the element from the array based on your condition.
Save the array back to UserDefaults.
Example-1: removing the element from array based on the index.
func remove(at index: Int) {
if let data = storage.data(forKey: "YOUR_KEY") {
do {
var arr = try JSONDecoder().decode([Item].self, from: data)
arr.remove(at: index)
let data = try JSONEncoder().encode(arr)
storage.set(data, forKey: "YOUR_KEY")
} catch {
print(error)
}
}
}
Example-2: removing a particular element from array.
func remove(element: Item) {
if let data = storage.data(forKey: "YOUR_KEY") {
do {
var arr = try JSONDecoder().decode([Item].self, from: data)
arr.removeAll { $0 === element }
let data = try JSONEncoder().encode(arr)
storage.set(data, forKey: "YOUR_KEY")
} catch {
print(error)
}
}
}
UserDefaults doesn't provide any API to manage the contents of a particular key. In fact, it doesn't care what kind of content is saved there.
So, what you need to do is: extract the array from UserDefaults, edit it and then save an updated array to UserDefaults.

how to update realm object based on the certain property in Realm?

I have products in my Realm database like this
I want to update my realm database based on productID, so I don't need to add another product over and over again. let say I want to update quantity of product that has productID = "a" to be 5.
I have tried to write something like this.
let selectedProductID = "a"
let productsInRealmDatabase = realm.objects(Product.self)
let productIndex = productsInRealmDatabase.index(where: {$0.productID == selectedProductID})
if let productIndex = productIndex {
do {
try realm.write {
var productRealm = productsInRealmDatabase[productIndex]
productRealm.quantity = 5
productsInRealmDatabase[productIndex] = productRealm // ERROR HERE
}
} catch {
// error Handling
}
}
but I got error in : productsInRealmDatabase[productIndex] = productRealm
Error Message: Cannot assign through subscript: subscript is get-only
so how to update realm object based on the certain property in Realm?
You should use Realm's own filter method which accepts an NSPredicate and returns an auto-updating Results instance rather than Swift's filter when operating on Realm collections. Than either update the properties of the fetched prouduct or create a new one and save that to Realm.
let selectedProductID = "a"
let productsInRealmDatabase = realm.objects(Product.self)
let matchingProduct = productsInRealmDatabase.filter("productID == %#", selectedProductID).first
if let matchingProduct = matchingProduct {
do {
try realm.write {
matchingProduct.quantity = 5
}
} catch {
// error Handling
}
} else {
let newProduct = Product()
newProduct.productID = selectedProductID
newProduct.quantity = 5
do {
try realm.write {
realm.add(newProduct)
}
} catch {
// error Handling
}
}
If you want your Products to be unique based on their productID property, you use also set productID as the primaryKey of your Object subclass.
class Product:Object {
#objc dynamic var productID = ""
...
override static func primaryKey() -> String? {
return "productID"
}
}
Try this -
let selectedProductID = "a"
let productsInRealmDatabase = realm.objects(Product.self)
let filteredProducts = productsInRealmDatabase.filter("productID = \(selectedProductID)")
do {
try realm.write {
filteredProducts.forEach { product in
product.quantity = 5
}
}
} catch {
// error Handling
}
While inserting data to your database inside the insert function mark update key as true and then try updating the value. eg:
static func insertData() {
//Your insertion code//
try! realm.write {
realm.add(request, update: true)
}
}
static func updateData(productId: String, quantity: Int) {
let product = self.getProductData(prodId: productId)
let realm = try! Realm()
try! realm.write {
product?.quantity = quantity
}
}
Hope this helps you out.

Add / Update custom object dictionaries array in swift 4

I have an array of dictionary with custom object in swift.
Now I am comparing the object for add & update.
The logic is as simple to add the data if not exist and update if any change in dictionary.
User is custom object type:
#objc public class User: NSObject , Mappable
from the getUserID i can able to get userID
The below code is execute in for loop from where i am passing User object.
var peopleList = [User]()
if self.peopleList.count > 0 {
if self.peopleList.contains(where: {$0.getUserID() == users.getUserID()})
{
// check for any update in dist
if let index = self.peopleList.index(of: users)
{
if users.isEqual(self.peopleList[index])
{
print("equal no updates")
}
else
{
print("need to updates objects..")
}
}
//already exist room
}
else
{
self.peopleList.append(users)
}
}
I know it may be related to equatable
so I am using below fuction
func isEqual<T: Equatable>(type: T.Type, a: Any, b: Any) -> Bool? {
guard let a = a as? T, let b = b as? T else { return nil }
return a == b
}
But I am getting index = nil.
Is there any idea or suggestion to solve it.
If any other way to do it efficiently them most welcome.
I think this simplified version should work
if self.peopleList.isEmpty, let user = self.peopleList.first(where: { $0.getUserID() == users.getUserID() }) {
if user == users {
// is equal
} else {
// do update
}
} else {
self.peopleList.append(users)
}

Copy RLMObject ,Modify and then save

So what im trying to do is, retrieve the object that is already saved on Realm, modify some properties and then save it again, keeping only one record on the database.
Heres my code :
Getting the Realm already saved user
if let user = User.query() {
user.latitude = String(latitude)
user.longitude = String(longitude)
user.save()
}
User query func, inside User Obj
static func query() -> User? {
return User.allObjects().toArray(User.self).first
}
func save() -> User {
RealmPersister.saveObjects([self])
return self
}
And the RealmPersister class func
class func saveObjects(objects: [RLMObject]?) {
autoreleasepool {
guard let objects = objects where objects.count > 0 else { return }
do {
let realm = RealmEncrypted.realm()
realm.beginWriteTransaction()
realm.addObjects(objects)
try realm.commitWriteTransaction()}
catch {
print("Realm did not write objects! \(objects)")
}
}
}
class func deleteObjects(objects: [RLMObject]?) {
autoreleasepool {
guard let objects = objects where objects.count > 0 else { return }
do {
let realm = RealmEncrypted.realm()
realm.beginWriteTransaction()
realm.deleteObjects(objects)
try realm.commitWriteTransaction()
} catch {
print("Realm did not delete objects! \(objects)")
}
}
}
This appears that you need to be using primary keys on the User object. This way you can retrieve the same object quickly via the primary key, modify it, and then save it without the possibility of creating duplicates.

Removing from array of dictionary

I use UserDefualt to save array of Dictionary:
let pref = NSUserDefaults.standardUserDefaults();
var fav=pref.arrayForKey("favRecipes")!;
fav.append(self.dict);
pref.setObject(fav, forKey: "favRecipes");
before i save another data i check if it already exist:
#IBAction func addToFavorites(sender: UIButton) {
//not exist
if !isFavorite(){
var fav=pref.arrayForKey("favRecipes")!;
fav.append(self.dict);
pref.setObject(fav, forKey: "favRecipes");
print("added");
} //exist
else{
;
}
}
private func isFavorite()->Bool{
var fav=pref.arrayForKey("favRecipes")!;
for r in fav{
if r["id"]! as! Int==id{
return true;
}
}
return false;
}
The purpose of this code is to add something to your favorites list, and if its already there u have the option to remove it.
for some reason i'm not succeeding to do the last part.
this my try so far:
func remove(event:UIAlertAction!){
var fav=pref.arrayForKey("favRecipes")!;
for r in fav{
if r["id"]! as! Int==id{
pref.removeObjectForKey("\(id)");
//pref.synchronize();
//fav=pref.arrayForKey("favRecipes")!;
//print(r["id"] as! Int);
}
}
}
ofcourse i tried to look and search about removing from dictionarys at userDefualt but nothing helps.
You have to change the array fav and write that array back into the userDefaults. There is no object with the key \(id) in the defaults, only an array for key favRecipes which in turn contains an entry for the key id.
func remove(event:UIAlertAction!){
var fav = pref.arrayForKey("favRecipes")!
fav = fav.filter { $0["id"] != id }
pref.setObject(fav, forKey: "favRecipes")
}

Resources