Adding One CoreData List to Another - ios

Let's say there are two favorite food lists: Johnny's List and Jane's List. They are both in CoreData, are separate entities, but have identical attributes. Both have four attributes: food name, secret ingredient, rating, and where to get it.
The user taps a button to merge the two lists. Specifically, Jane's list should now show up in Johnny's BUT her items should go first.
A very simple example set of lists:
Pre Merge - Johnny's List (only has 1 record)
Apple Pie -
Apples -
4.5 -
Susan's Diner
Pre Merge - Jane's List (has 2 records)
Turkey Dinner -
Turkey -
5.0 -
Mom's house -
BBQ Dinner -
Pulled Pork -
4.0 -
Route 6 Rib Shack
Post Merge - Johnny's List (has 3 records)
Turkey Dinner -
Turkey -
5.0 -
Mom's house
BBQ Dinner -
Pulled Pork -
4.0 -
Route 6 Rib Shack
Apple Pie -
Apples -
4.5 -
Susan's Diner
Johnny's new list of 3 items should save over Johnny's old list in CoreData. Jane's list should be cleared.

Solved!
There are likely several ways to solve this question but what I received for answers and found online weren't doing the trick. I took a shot at just writing the code and it works!
My Code
Here's my merge function.
It is passed only one parameter: the destination name. That is because my source list context was already setup outside the function.
Alternatively you could pass two parameters, the name of List A and List B, and set both contexts up in the function.
My CoreData fetch also has a sort predicate which you might not need.
func merge_ListA_Into_ListB (targetList: String) {
//Setup Targetlist context
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//Get sorted CoreData list and assign it to targetList_Cntxt
let fetchRequest = NSFetchRequest(entityName: targetList)
let sortDescriptor = NSSortDescriptor(key: "displayOrder", ascending: true)
fetchRequest.sortDescriptors = [ sortDescriptor ]
do {
let fetchedResults = try managedContext.executeFetchRequest(fetchRequest) as? [NSManagedObject]
if let results = fetchedResults {
targetList_Cntxt = results
}
} catch { print(error) }
for i in (0..<listA_Cntxt.count).reverse() {
//Grab a ListA task item
let itemToMove = listA_Cntxt[i]
//Assign the ListA item's contents to variables
let nameToTransfer = itemToMove.valueForKey("name") as? String
let descToTransfer = itemToMove.valueForKey("desc") as? String
//Assign the ListA item's contents to the target's object
let newItem = NSEntityDescription.insertNewObjectForEntityForName(targetList, inManagedObjectContext: managedContext)
newItem.setValue(nameToTransfer, forKey: "name")
newItem.setValue(descToTransfer, forKey: "desc")
//Insert the item!!
targetList_Cntxt.insert(newItem, atIndex: 0)
}
//Calls function that updates each records sort/display #
update_TargetDisplayOrder()
try! managedContext.save()
print("List merged into \(targetList).")
}
Good luck!

Related

Delete number phone Contact - Swift 3 - 4

I want to delete a contact number, I use ContactsUI
//only do this to the first contact matching our criteria
guard let contact = contacts?.first else{
return
}
let editContact = contact.mutableCopy() as! CNMutableContact
editContact.phoneNumbers[1]..... ?
in editContact.phoneNumbers[1].. I want to eliminate that number that is in that position
to edit it, I edit it in this way. and it works well
editContact.phoneNumbers[1] = CNLabeledValue(label: "home",
value: CNPhoneNumber(stringValue: "1234567"))
but how do I eliminate it
phoneNumbers is an array. Remove the desired element like you would any other array value:
let editContact = contact.mutableCopy() as! CNMutableContact
editContact.phoneNumbers.remove(at: 1)
Of course I'd make sure there are at least 2 phone numbers before doing that.

How to save one record for multiple department using core data in swift 3

I have two tables name Employee & Department, I have given relationship like following ways,
See bellow my Department table
& this is my Employee table
func saveEmpDetails(empId: String, andEmployeeName empName: String, andDeptId deptId: String, andDeptName departName: String, andProfile profileName: String, createdOn minutesAgo:Double , empQuote quote:String) {
// Reading AppDelegate
let appDelegate = UIApplication.shared.delegate as! AppDelegate
// Getting managed object context
let managedObjectContext = appDelegate.persistentContainer.viewContext
let empID:Int? = Int(empId)
let _predicate = NSPredicate(format: "empId=%#", empId)
let _fetchRecord: Employee? = isRecordExist(withEntiryName: "Employee", with: _predicate) as? Employee
if _fetchRecord != nil {
// Update Employee record as managed objext
}else {
// Inserting Employee record as managed objext
let _empInformation: Employee? = NSEntityDescription.insertNewObject(forEntityName: "Employee", into: managedObjectContext) as? Employee
_empInformation?.empId = Int32(empID!)
_empInformation?.empName = empName
_empInformation?.empProfile = profileName
_empInformation?.createdOn = Date().addingTimeInterval(-minutesAgo * 60) as NSDate
_empInformation?.empQuote = quote
let departmentRecord: Department? = NSEntityDescription.insertNewObject(forEntityName: "Department", into: managedObjectContext) as? Department
// departmentRecord?.departName = departName
// departmentRecord?.departId = Int32(deptId)!
// departmentRecord?.addToEmployees(_empInformation!)
let allDepartments = NSSet(array : ["10", "11"]) // Set<String>
departmentRecord?.addToEmployees(allDepartments)
departmentRecord?.addToEmployees(_empInformation!)
}
// Saving the employee details using save context
appDelegate.saveDBContext()
}
Now i want to save the one record for multiple departments, lets assume ABC employee work in iOS department & Android
My Question is : how can i save that ABCemployee record at one time. I have given my lot of efforts & did stack-overflow but didn't come across such a condition.
Can anyone help to complete my tutorial.
Change your employee relationship from 'to one' to 'to many' so that the relationship between the two entities becomes 'many to many'. Then your employee will have a Set of departments. Just look up many to many core data relationships, there's a lot of info about it out there.

Core Data - Cascade delete in relationship not working

insertion code :
let dbObj: NSEntityDescription? = NSEntityDescription.entity(forEntityName: "CartTable", in: self.appDelegate.coreDataStack.managedObjectContext)
if dbObj != nil {
let myCartObj: CartTable = CartTable(entity: dbObj!, insertInto: self.appDelegate.coreDataStack.managedObjectContext)
myCartObj.menuId = self.itemListDataResponseModel?.menuItemId
myCartObj.menuName = self.itemListDataResponseModel?.menuItemName
myCartObj.menuPrice = self.itemListDataResponseModel?.price
//myCartObj.menuQuantity
//myCartObj.menuTotalPrice
myCartObj.userId = AppDataStoreManager.getUserDefault(KeyToReturnValye: "userId") as! String?
myCartObj.imageUrl = self.itemListDataResponseModel?.imgPath
myCartObj.desc = self.itemListDataResponseModel?.description
myCartObj.locationId = AppDataStoreManager.getUserDefault(KeyToReturnValye: "locationId") as! String?
myCartObj.locationName = AppDataStoreManager.getUserDefault(KeyToReturnValye: "locationName") as! String?
myCartObj.vendorId = self.vendorObject?.vendorId
myCartObj.vendorName = self.vendorObject?.vendorName
self.appDelegate.coreDataStack.saveContext()
deletion code :
self.appDelegate.coreDataStack.managedObjectContext.delete(obj)
self.appDelegate.coreDataStack.saveContext()
when i delete an item from cart table then all the related entries regarding to same menu id from carttablesidemenu item table must have to be deleted.
currently when i delete entry from carttable then it getting deleted but entries in carttable side menu not getting deleted that means relationship not working
NSManagedObject automatically creates its accessors methods so we have to use that methods to maintain relationships.

Add and Delete CoreData based on attribute value search match

Setup: iOS 9, Swift, XCODE 7.1 Beta
Goal is to build shopping cart functionally for which I need unique values in CoreData.
I have a UITableView in which data (Product name, Cost, Quantity, ID) is uploaded from Parse backend. Each TableView custom cell has a button, tapping which saves the selected row data in CoreData.
I don't want to have duplicate product in the cart, so before saving I want to check if the cart already have the product. If it has, I want to replace the cart with currently selected data. If not, just want to add a new product in the cart.
My CoreData setup is simple.
Entity name = Cart
Attributes = pName(type String), pCost(type
Int), pQuantity(type Int), orderID(type String)
Add product to the Cart button code is as below:
// Product data is retrieved in these variable
var pNam = NSMutableArray()
var pCost = NSMutableArray()
var pQty = NSMutableArray()
var pObjectID = NSMutableArray()
// Add to Cart button ....
let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(indexPath) as! ProductMenuTableViewCell! // Custom cell in which the button add to Cart button is placed
let entityDescription = NSEntityDescription.entityForName("Cart", inManagedObjectContext: managedObjectContext!)
let cart = Cart(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext)
cart.pName = pNam[indexPath.row].description
cart.pCost = pCst[indexPath.row].integerValue!
cart.pQuantity = pQty[indexPath.row].integerValue!
cart.orderID = pObjectID[indexPath.row].description
var error: NSError?
do {
try managedObjectContext?.save()
} catch let error1 as NSError {
error = error1
}
if let err = error {
print(err.localizedFailureReason)
} else {
print("Saved")
}
Should I directly use cell to add values to CoreData? For ex: cart.pName = cell.pName.text! or there is a better way to do it? Anyone know how to solve this?
Your data setup is absurd. You have 4 arrays for the 4 attributes of n objects. If for any reason the sorting of an array changes, or an element is dropped or added, you have to make sure the same happens with all the other arrays, a maintenance nightmare! How do you expand this model if later you have 15 attributes. Use 15 arrays? This is completely crazy.
Instead, you should have an array of objects - ideally Core Data objects - with the appropriate attributes grouped together. You can always keep a flag to indicate that you want to discard these items later rather then persist them in the database.
Now you do not have to decide to create or update: simply set the delete flag to false.
You need to search for an existing Cart object with the correct name; if there is no matching Cart, then create a new one. Something like this:
var cart : Cart
let requiredName = pNam[indexPath.row].description
let entityDescription = NSEntityDescription.entityForName("Cart", inManagedObjectContext: managedObjectContext!)
let fetchRequest = NSFetchRequest()
fetchRequest.entity = entityDescription!
fetchRequest.predicate = NSPredicate(format:"pName == %#",requiredName)
do {
let results = try self.managedObjectContext?.executeFetchRequest(fetchRequest) as! [Cart]
if results.count == 0 { // not found, so create new...
cart = Cart(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext)
cart.pName = requiredName
} else { // found at least one, so use the first...
cart = results[0]
}
// Now update the other attribute values:
cart.pCost = pCst[indexPath.row].integerValue!
cart.pQuantity = pQty[indexPath.row].integerValue!
cart.orderID = pObjectID[indexPath.row].description
} catch {
print("Error fetching")
}
Regarding your secondary question, personally I would use your current approach: use the row as an index on your dataSource arrays, i.e. don't directly use the values from the cell's labels etc.

CoreData Object Move Between Entities Not Working

I have two entities and they have the exact same three attributes (name, desc, displayOrder), both have a handful of records, and my goal is to add/insert every item from "Entity 1" into "Entity 2".
Close, But No Cigar
I think my code is quite close. The console print out shows my code is successfully sending each item in "Entity 1" to "Entity 2" and saving it. BUT they save over each other! The first item is moved and saved, then the second item is moved but copies over the item that was previously moved. End result: only the last item moved actually shows up in the final "Entity 2".
Question: How do I fix this?
#IBAction func testOutMoveList(sender: AnyObject) {
//Setup 'Do Later' context
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let new_Ent2_Item = NSEntityDescription.insertNewObjectForEntityForName("Entity2", inManagedObjectContext: managedContext)
//Get sorted CoreData list and assign it to targetList_Cntxt
let fetchRequest = NSFetchRequest(entityName: "Entity2")
let sortDescriptor = NSSortDescriptor(key: "displayOrder", ascending: true)
fetchRequest.sortDescriptors = [ sortDescriptor ]
do {
let fetchedResults = try managedContext.executeFetchRequest(fetchRequest) as? [NSManagedObject]
if let results = fetchedResults {
entity2_Cntxt = results
}
} catch {
print(error)
}
for i in 0..<entity1.count {
//Grab a Today task item
let itemToMove = entity1_Cntxt[i]
//Assign the Today item's contents to variables
let nameToTransfer = itemToMove.valueForKey("name") as? String
let descToTransfer = itemToMove.valueForKey("desc") as? String
//Assign the Today item's contents to the target's 'task' object
new_Ent2_Item.setValue(nameToTransfer, forKey: "name")
new_Ent2_Item.setValue(descToTransfer, forKey: "desc")
//Insert the item!!
entity2_Cntxt.insert(new_Ent2_Item, atIndex: 0)
}
//Updates target list in Core Data after append, delete, and drag/drop
func update_TargetDisplayOrder() {
for i in 0..<entity2_Cntxt.count {
let item = entity2_Cntxt[i]
item.setValue( i, forKey: "displayOrder" )
}
}
Possible Clue: I have noticed that the displayOrder doesn't seem to be updating correctly. The first item should be 0, the second should be 1, etc but instead each time the code cycles the lowest displayOrder is 1 higher (A three item list might start with values 2,3,4 - then my code moves/copies another item to entity 2 and the display order values are: 3,4,5)
Question: What code can I add or fix to make this transfer I'm attempting work!?!
Bonus question: Post-transfer how do I quickly/easily clear all the values from "Entity 1"
The short answer is that you need to move this line:
let new_Ent2_Item = NSEntityDescription.insertNewObjectForEntityForName("Entity2", inManagedObjectContext: managedContext)
so that it is inside the for loop:
for i in 0..<entity1.count {
//Grab a Today task item
let itemToMove = entity1_Cntxt[i]
// Create the corresponding new Entity2 object:
let new_Ent2_Item = NSEntityDescription.insertNewObjectForEntityForName("Entity2", inManagedObjectContext: managedContext)
//Assign the Today item's contents to variables
let nameToTransfer = itemToMove.valueForKey("name") as? String
let descToTransfer = itemToMove.valueForKey("desc") as? String
//Assign the Today item's contents to the target's 'task' object
new_Ent2_Item.setValue(nameToTransfer, forKey: "name")
new_Ent2_Item.setValue(descToTransfer, forKey: "desc")
//Insert the item!!
entity2_Cntxt.insert(new_Ent2_Item, atIndex: 0)
}
To explain: the insertNewObjectForEntityForName is what actually creates the new Entity2 object. In its original position, that line is run only once, so only one Entity2 object is created. Your for loop then changes its attribute values and inserts it at the start of the entity2_Cntxt array (multiple times). Note that the last step in the for loop, entity2_Cntxt.insert(new_Ent2_Item, atIndex: 0) does not create a new object, or copy new_Ent2_Item, it just inserts it at the start of the array. With the amended code, a new Entity2 object will be created each time through the loop.
Regarding the displayOrder problem, if you inspect the entity2_Cntxt array each time through the loop, you should find (with your original code) that the array contains the same Entity2 object several times, followed by the objects obtained from the fetch. Suppose entity2_Cntxt contains the new object three times (at indexes 0,1,2). Your update_TargetDisplayOrder method will then set that object's displayOrder to 0, then 1, then 2. And then the objects returned by the fetch will have displayOrder 3, 4, etc. I think this should all come good when you move the insertNewObjectForEntityForName as above.

Resources