Storing with CoreData - ios

my app is very simple: I have one tableview to store recipe *names and, for each recipe name, another tableview with several *ingredients for each recipe.
I already managed to save the name and the ingredients with CoreData, but here is the problem: when I press to add a NEW recipe name and enter the ingredients table view area, the ingredients saved for the previous recipe are there! How do I clear the table view to start a new one?
Also, my table views does not get updated immediately, I have to close the app and open it again. How do I fix it?
Note: If my question is too hard to understand, I can post some code! Thanks in advance, everyone =)
EDIT
code:
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {
#IBOutlet var tableView: UITableView!
var imageList: [UIImage] = []
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultsController: NSFetchedResultsController?
override func viewDidLoad() {
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchName(), managedObjectContext: moc!, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController?.delegate = self
fetchedResultsController?.performFetch(nil)
tableView.reloadData()
}
func fetchName() -> NSFetchRequest {
var fetchRequest = NSFetchRequest(entityName: "Details")
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.predicate = nil
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.fetchBatchSize = 20
return fetchRequest
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController?.sections?[section].numberOfObjects ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("recipeCell", forIndexPath: indexPath) as! UITableViewCell
if let recipeCell = fetchedResultsController?.objectAtIndexPath(indexPath) as? Details {
cell.textLabel?.text = recipeCell.name
}
return cell
}
}
-
import UIKit
import CoreData
class InfoViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UITableViewDelegate {
#IBOutlet var nameField: UITextField!
#IBOutlet var imageView: UIImageView!
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
override func viewDidLoad() {
super.viewDidLoad()
//Pick the image by tap
let tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "chooseImage:")
tapGestureRecognizer.numberOfTapsRequired = 1
imageView.addGestureRecognizer(tapGestureRecognizer)
imageView.userInteractionEnabled = true
}
//Pick the image by tapping, accessing the photoLibrary
func chooseImage(recognizer: UITapGestureRecognizer) {
let imagePicker: UIImagePickerController = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(imagePicker, animated: true, completion: nil)
}
//Put the selected image into the screen
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject:AnyObject]) {
let pickedImage: UIImage = (info as NSDictionary).objectForKey(UIImagePickerControllerOriginalImage) as! UIImage
// small picture
let smallPicture = scaleImageWith(pickedImage, newSize: CGSizeMake(288,148))
var sizeOfImageView:CGRect = imageView.frame
sizeOfImageView.size = smallPicture.size
imageView.frame = sizeOfImageView
imageView.image = smallPicture
picker.dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
picker.dismissViewControllerAnimated(true, completion: nil)
}
func scaleImageWith(image:UIImage, newSize: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image.drawInRect(CGRectMake(0,0, newSize.width, newSize.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
#IBAction func addButton(sender: AnyObject) {
let entityDescription = NSEntityDescription.entityForName("Details", inManagedObjectContext: moc!)
let details = Details(entity: entityDescription!, insertIntoManagedObjectContext: moc)
details.name = nameField.text
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Ingredient \(nameField.text) saved successfully!")
}
if let navigation = navigationController {
navigation.popViewControllerAnimated(true)
}
}
}
-
import UIKit
import CoreData
class IngredientListViewController: UIViewController, NSFetchedResultsControllerDelegate {
#IBOutlet var tableView: UITableView!
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultsController: NSFetchedResultsController?
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchIngredient(), managedObjectContext: moc!, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController?.delegate = self
fetchedResultsController?.performFetch(nil)
tableView.reloadData()
}
func fetchIngredient() -> NSFetchRequest {
var fetchRequest = NSFetchRequest(entityName: "Ingredients")
let sortDescriptor = NSSortDescriptor(key: "ingredients", ascending: true)
fetchRequest.predicate = nil
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.fetchBatchSize = 20
return fetchRequest
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController?.sections?[section].numberOfObjects ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ingCell", forIndexPath: indexPath) as! UITableViewCell
if let recipeCell = fetchedResultsController?.objectAtIndexPath(indexPath) as? Ingredients {
cell.textLabel?.text = recipeCell.ingredients
}
return cell
}
}
-
import UIKit
import CoreData
class IngredientViewController: UIViewController {
#IBOutlet var nameField: UITextField!
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func addButton(sender: AnyObject) {
let entityDescription = NSEntityDescription.entityForName("Ingredients", inManagedObjectContext: moc!)
let details = Ingredients(entity: entityDescription!, insertIntoManagedObjectContext: moc)
details.ingredients = nameField.text
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println("\(status)")
} else {
println("Ingredient \(nameField.text) saved successfully!")
}
if let navigation = navigationController {
navigation.popViewControllerAnimated(true)
}
}
}
and models:
import Foundation
import CoreData
class Ingredients: NSManagedObject {
#NSManaged var ingredients: String
#NSManaged var relationship: NSSet
}
import Foundation
import CoreData
class Details: NSManagedObject {
#NSManaged var name: String
#NSManaged var relationship: Ingredients
}

In outline:
You need to amend your model: currently each Details object can have only one Ingredients. I suspect you need this relationship to be "to many" so a recipe can have many ingredients.
You need to add a var (of type Details?) to your IngredientListViewController. This will represent the chosen Recipe. (eg. var chosenRecipe : Details?)
In fetchIngredient, you need to add a predicate to the fetch, to limit the results to the chosen recipe. eg. fetch.predicate = NSPredicate(format:"ANY relationship == %#", chosenRecipe)
Before segueing to this VC, you need to set the chosenRecipe (probably in prepareForSegue, or didSelectRowAtIndexPath in the preceding table view).
To get your TV to update automatically, use the fetchedResultsController delegate methods. (Have you implemented these?)

Related

Trouble with multiple-sectioned TableView in Swift

I apologize in advance if this is confusing. I'm new to Swift with no prior experience and learning.
Basically, I have a UITableView that pulls its data form another viewController with four text fields. The data is saved and added to the tableView (only displaying the two of the fields in the cell). When the cell is selected it segues back to the viewController and adds the data in the appropriate text fields. This also utilized CoreData and NSFetchResultsController. All of this is working properly so far, just wanted to give a little back ground on whats going on.
The Problem...
I am trying to get the tableView to display the data in two sections. I want the first section (section 0) to display the data added to the list created by adding the text fields on the viewController. However, the tableView adds first row as the first section (with the header correct) and then adds the second row (and on) as the second section (section 1)(with section header). I want to add all new items from the viewController to section 0, leaving section 1 blank for when I figure out how to cross items off section 0 and move to section 1 by selecting the row (Coming in the future).
I am new to this site as well and could not figure out how to post my code. If anyone needs to look through it you may have to walk me through adding it. Also, I have trouble converting Objective C to Swift please keep that in mind while answering. Thank you!! and I apologize for being difficult.
(tableView Controller "SList")
class ShoppingList: UIViewController, NSFetchedResultsControllerDelegate, UITableViewDataSource, UITableViewDelegate {
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var frc : NSFetchedResultsController = NSFetchedResultsController()
func itemFetchRequest() -> NSFetchRequest{
let fetchRequest = NSFetchRequest(entityName: "SList")
let primarySortDescription = NSSortDescriptor(key: "slitem", ascending: true)
let secondarySortDescription = NSSortDescriptor(key: "slcross", ascending: true)
fetchRequest.sortDescriptors = [primarySortDescription, secondarySortDescription]
return fetchRequest
}
func getFetchRequetController() ->NSFetchedResultsController{
frc = NSFetchedResultsController(fetchRequest: itemFetchRequest(), managedObjectContext: moc, sectionNameKeyPath: "slitem", cacheName: nil)
return frc
}
#IBOutlet weak var tableView: UITableView!
#IBAction func AddNew(sender: AnyObject) {
frc = getFetchRequetController()
frc.delegate = self
do {
try frc.performFetch()
} catch _ {
print("Failed to perform inital fetch.")
return
}
self.tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
frc = getFetchRequetController()
frc.delegate = self
do {
try frc.performFetch()
} catch _ {
print("Failed to perform inital fetch.")
return
}
self.tableView.reloadData()
//TableView Background Color
self.tableView.backgroundColor = UIColor.clearColor()
tableView.reloadData()
self.navigationItem.leftBarButtonItem = self.editButtonItem()
self.tableView.separatorColor = UIColor.blackColor()
}
override func viewDidDisappear(animated: Bool) {
frc = getFetchRequetController()
frc.delegate = self
do {
try frc.performFetch()
} catch _ {
print("Failed to perform inital fetch.")
return
}
self.tableView.reloadData()
}
//TableView Data
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
let managedObject:NSManagedObject = frc.objectAtIndexPath(indexPath) as! NSManagedObject
moc.deleteObject(managedObject)
do {
try moc.save()
} catch _ {
print("Failed to save.")
return
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
let numberOfSections = frc.sections?.count
return numberOfSections!
}
//table section headers
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String?{
let sectionHeader = "Items - #\(frc.sections![section].numberOfObjects)"
let sectionHeader1 = "Crossed Off Items - #\(frc.sections![section].numberOfObjects)"
if (section == 0) {
return sectionHeader
}
if (section == 1){
return sectionHeader1
}else{
return nil
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let numberOfRowsInSection = frc.sections?[section].numberOfObjects
return numberOfRowsInSection!
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let items = frc.objectAtIndexPath(indexPath) as! SList
cell.backgroundColor = UIColor.clearColor()
cell.textLabel?.text = "\(items.slitem!) - Qty: \(items.slqty!)"
cell.textLabel?.font = UIFont.systemFontOfSize(23)
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
tableView.reloadData()
}
//segue to add/edit
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "edit" {
let cell = sender as! UITableViewCell
let indexPath = tableView.indexPathForCell(cell)
let SListController:SLEdit = segue.destinationViewController as! SLEdit
let items:SList = frc.objectAtIndexPath(indexPath!) as! SList
SListController.item = items
}
}
}
(ViewController "SLEdit")
class SLEdit: UIViewController {
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
#IBOutlet weak var slitem: UITextField!
#IBOutlet weak var sldesc: UITextField!
#IBOutlet weak var slqty: UITextField!
#IBOutlet weak var slprice: UITextField!
var item: SList? = nil
override func viewDidLoad() {
super.viewDidLoad()
if item != nil{
slitem.text = item?.slitem
sldesc.text = item?.sldesc
slqty.text = item?.slqty
slprice.text = item?.slprice
}
// "x" Delete Feature
self.slitem.clearButtonMode = UITextFieldViewMode.WhileEditing
self.sldesc.clearButtonMode = UITextFieldViewMode.WhileEditing
self.slqty.clearButtonMode = UITextFieldViewMode.WhileEditing
self.slprice.clearButtonMode = UITextFieldViewMode.WhileEditing
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func dismissVC() {
navigationController?.popViewControllerAnimated(true)
}
#IBAction func saveButton(sender: AnyObject) {
if item != nil {
edititems()
} else {
createitems()
}
dismissVC()
}
func createitems() {
let entityDescription = NSEntityDescription.entityForName("SList", inManagedObjectContext: moc)
let item = SList(entity: entityDescription!, insertIntoManagedObjectContext: moc)
item.slitem = slitem.text
item.sldesc = sldesc.text
item.slqty = slqty.text
item.slprice = slprice.text
if slitem.text == nil{
createitems()
}else{
edititems()
}
do {
try moc.save()
} catch _ {
return
}
}
func edititems() {
item?.slitem = slitem.text!
item?.sldesc = sldesc.text!
item?.slqty = slqty.text!
item?.slprice = slprice.text!
do {
try moc.save()
} catch {
return
}
}
}
I think the problem lies in your FRC configuration:
frc = NSFetchedResultsController(fetchRequest: itemFetchRequest(), managedObjectContext: moc, sectionNameKeyPath: "slitem", cacheName: nil)
Because sectionNameKeyPath is slitem, the FRC creates a new section for each different value of slitem.
If the slcross attribute is used to indicate that the item has been crossed off the list, specify that as the sectionNameKeyPath:
frc = NSFetchedResultsController(fetchRequest: itemFetchRequest(), managedObjectContext: moc, sectionNameKeyPath: "slcross", cacheName: nil)
You will also need to modify the sorting of the fetch request (it MUST be sorted so that all items in a given section are together):
let primarySortDescription = NSSortDescriptor(key: "slcross", ascending: true)
let secondarySortDescription = NSSortDescriptor(key: "slitem", ascending: true)
fetchRequest.sortDescriptors = [primarySortDescription, secondarySortDescription]

How to fetch data from specific relationship entity in Swift?

I have two relationship entities in Core Data. In the first entity I add names of companies in attribute. Then I move to second UIViewController and I add other attributes of specific company in the second entity which is relationship with the first entity. Also I have two UITableViewControllers, the first UITableViewController shows names of every company in cell. When I selected the specific company I move to the second UITableViewController. I want the second UITableViewController shows data of the specific company which I selected. I tried several different methods but I could not to make how I want. How can I make it?
The second UITableViewController code
override func viewDidLoad() {
super.viewDidLoad()
self.definesPresentationContext = true
println(currentCompany)
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: managedObjectContext, sectionNameKeyPath: "activityCompany", cacheName: nil)
fetchedResultsController.delegate = self
fetchedResultsController.performFetch(nil)
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - var and let
var currentCompany: String!
var managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
// MARK: - fetchResultsController
var fetchedResultsController: NSFetchedResultsController!
func fetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Information")
var sortDescriptor = NSSortDescriptor(key: "company", ascending: true)
fetchRequest.fetchBatchSize = 50
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = NSPredicate(format: "company contains [c] %#", currentCompany)
return fetchRequest
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultsController.sections?.count ?? 0
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController.sections?[section].numberOfObjects ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
if var dataForCell = fetchedResultsController.objectAtIndexPath(indexPath) as? Information {
cell.textLabel?.text = dataForCell.activityCompany
cell.detailTextLabel?.text = dataForCell.foundedCompany
}
return cell
}
Entities
import Foundation
import CoreData
#objc(Company)
class Company: NSManagedObject {
#NSManaged var nameCompany: String
#NSManaged var information: NSSet
}
import Foundation
import CoreData
#objc(Information)
class Information: NSManagedObject {
#NSManaged var activityCompany: String
#NSManaged var foundedCompany: String
#NSManaged var company: Company
}
I save data into entites the following method.
// MARK: - #IBActions
#IBAction func saveData(sender: UIBarButtonItem) {
var companyEntity = NSEntityDescription.insertNewObjectForEntityForName("Company", inManagedObjectContext: managedObjectContext) as! NSManagedObject
var informationEntity = NSEntityDescription.insertNewObjectForEntityForName("Information", inManagedObjectContext: managedObjectContext) as! NSManagedObject
companyEntity.setValue(currentName, forKey: "nameCompany")
informationEntity.setValue(activityTextField.text, forKey: "activityCompany")
informationEntity.setValue(foundedTextField.text, forKey: "foundedCompany")
companyEntity.setValue(NSSet(object: informationEntity), forKey: "information")
var error: NSError?
managedObjectContext.save(&error)
var story = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
var naviController = story.instantiateViewControllerWithIdentifier("firstNavi") as! UINavigationController
presentViewController(naviController, animated: true, completion: nil)
}
I solved it.
func fetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Information")
var sortDescriptor = NSSortDescriptor(key: "activityCompany", ascending: true)
fetchRequest.fetchBatchSize = 50
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = NSPredicate(format: "company.nameCompany contains [c] %#", currentCompany)
return fetchRequest
}

TableController doesn't show the data from Core-data

I want to make simple Contact by using core-data and tableView for practicing CoreData.
So I have watched youtube and write it's code.
Finally, I thought that I got this, I made by myself, but tableView doesn't contain any data, I could compile though. Could anyone tell me what is wrong? and hopefully tell me how to check the stored data in core-data?
import UIKit
import CoreData
class ViewController: UIViewController {
var context = (UIApplication.sharedApplication().delegate as!AppDelegate).managedObjectContext
var stores : Contact? = nil
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var phoneTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
if stores != nil {
nameTextField.text = stores?.name
phoneTextField.text = stores?.phone
context?.save(nil)
} }
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func saveTapped(sender: AnyObject) {
let context = self.context
// Get the description of the entity
if stores != nil { let storeDescription = NSEntityDescription.entityForName("stores", inManagedObjectContext: context!)
// Then, We Create the Managed Object to be inserted into the cored data
stores = Contact(entity: storeDescription!, insertIntoManagedObjectContext: context)
}
// set the attributes
stores?.name = nameTextField.text
stores?.phone = phoneTextField.text
context!.save(nil) // Save The object
let alert = UIAlertView(title: "저장 완료", message: "\(nameTextField.text)님이 전화번호부에 저장 되었습니다", delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
}
And here is my tableviewcontroller.
import UIKit
import CoreData
class TableViewController: UITableViewController , NSFetchedResultsControllerDelegate{
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var frc : NSFetchedResultsController = NSFetchedResultsController()
var stores = [Contact]()
override func viewDidLoad() {
super.viewDidLoad()
frc.delegate = self
frc.performFetch(nil)
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func viewWillAppear(animated: Bool) {
var error:NSError?
let request = NSFetchRequest(entityName: "Contact")
stores = context?.executeFetchRequest(request, error: &error) as! [Contact]
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return stores.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
let save = stores[indexPath.row]
cell.textLabel!.text = save.name
cell.detailTextLabel!.text = save.phone
return cell
}
func getFetchedResultsController() ->NSFetchedResultsController {
frc = NSFetchedResultsController(fetchRequest: listFetchRequest(), managedObjectContext: context!, sectionNameKeyPath: nil, cacheName: nil)
return frc
}
func listFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Contact")
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
return fetchRequest
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if segue.identifier == "edit"
{
let destViewController = segue.destinationViewController as! ViewController
let indexPath = self.tableView.indexPathForSelectedRow()
let row = indexPath?.row
destViewController.stores = stores[row!]
}
}
}
Update ----Since I fixed my viewController, It works. It would be like
import UIKit
import CoreData
class ViewController: UIViewController {
var context = (UIApplication.sharedApplication().delegate as!AppDelegate).managedObjectContext
var stores : Contact? = nil
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var phoneTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
if stores != nil {
nameTextField.text = stores?.name
phoneTextField.text = stores?.phone
context?.save(nil)
} }
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func saveTapped(sender: AnyObject) {
if stores != nil {
edit()
}else {
addNew()
}
navigationController?.popViewControllerAnimated(true)
}
func addNew() {
let description = NSEntityDescription.entityForName("Contact", inManagedObjectContext: context!)
let stores = Contact(entity: description!, insertIntoManagedObjectContext: context)
stores.name = nameTextField.text
stores.phone = phoneTextField.text
context?.save(nil)
}
func edit() {
stores!.name = nameTextField.text
stores!.phone = phoneTextField.text
context?.save(nil)
}
}
1. How to locate and View the SQLlite file.
You can find out the path of the .sqlite file using the below function.
func applicationDirectoryPath() -> String {
return NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last! as! String
}
Then use any third party tools to view the content of the Sqlite database like SQLLite Manager (a firefox addon)
2. Displaying data in TableView.
In your tableViewController, instead of using stores variable Use NSFetchedResultController (frc) to retrieve and show the data in TableView. Check out this link for using NSFetchedResultController with TableViewController.

CoreData - TableView does not get updated

So, I'm struggling to learn how to handle CoreData properly.
Here is my code:
import UIKit
import CoreData
class IngredientsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultsController: NSFetchedResultsController?
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchIngredients(), managedObjectContext: moc!, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController?.delegate = self
fetchedResultsController?.performFetch(nil)
}
func fetchIngredients() -> NSFetchRequest {
var fetchRequest = NSFetchRequest(entityName: "DetailsForRecipe")
let sortDescriptor = NSSortDescriptor(key: "ingredients", ascending: true)
fetchRequest.predicate = nil
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.fetchBatchSize = 20
return fetchRequest
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController?.sections?[section].numberOfObjects ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ingCell", forIndexPath: indexPath) as! UITableViewCell
if let ingCell = fetchedResultsController?.objectAtIndexPath(indexPath) as? DetailsForRecipe {
cell.textLabel?.text = ingCell.ingredients
}
return cell
}
}
and
import UIKit
import CoreData
class SingleIngredientViewController: UIViewController {
#IBOutlet var ingField: UITextField!
var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func addIng(sender: AnyObject) {
let entityDescription = NSEntityDescription.entityForName("DetailsForRecipe", inManagedObjectContext: moc!)
let details = DetailsForRecipe(entity: entityDescription!, insertIntoManagedObjectContext: moc)
details.ingredients = ingField.text
var error: NSError?
moc?.save(&error)
if let err = error {
var status = err.localizedFailureReason
println(status)
} else {
println("Ingredient \(ingField.text) saved successfully!")
}
if let navigation = navigationController {
navigation.popViewControllerAnimated(true)
}
}
}
My model:
import Foundation
import CoreData
class DetailsForRecipe: NSManagedObject {
#NSManaged var name: String
#NSManaged var ingredients: String
#NSManaged var image: NSData
}
The app should insert the ingredient name in the text field, save it into coreData, then it should be retrieved in the table view. When I text the ingredient name and press "add", the prinln message says it was successfully saved, but the table view does not update.
What am I doing wrong here? I'm not a developer, I've read many tutorials on how to do this, but it is very confusing! So forgive me about this.
Thanks in advance!
I haven't read your full source code, but by doing an immediate glance, I don't see that you've called the tableview's reloadData function. If you don't have an IBOutlet set up for your table view, you will want to do that and then call reloadData() on it.
Call reloadData() on your table view after the change is made.

Adding sections, separated by dates, to UITableView in Swift CoreData

Can somebody tell me how to add sections with date using CoreData?
I have detailViewController which store all data from CoreDate, and AddTableViewController when we write some data.
Detail View Controller
import UIKit
import CoreData
class DetailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate, AddTableViewControllerDelegate {
#IBOutlet weak var tableView: UITableView!
var detailTaskModel: Items!
var costsValues:Int!
#IBOutlet weak var sumLabel: UILabel!
// CoreData
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext
var fetchedResultsController: NSFetchedResultsController = NSFetchedResultsController()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
fetchedResultsController = getFetchedResultsController()
fetchedResultsController.delegate = self
fetchedResultsController.performFetch(nil)
costsValues = getAccountCountSum()
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController.sections![section].numberOfObjects
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: DetailTableViewCell = tableView.dequeueReusableCellWithIdentifier("detailCell") as DetailTableViewCell
let thisCost = fetchedResultsController.objectAtIndexPath(indexPath) as Costs
cell.nazwaWydatkuLabel.text = thisCost.costsName
cell.wartośćLabel.text = "\(thisCost.costsValue) zł"
return cell
}
#IBAction func addCostButtonPressed(sender: UIBarButtonItem) {
self.performSegueWithIdentifier("addCostVC", sender: self)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultsController.sections!.count
}
override func viewDidAppear(animated: Bool) {
costsValues = getAccountCountSum()
refreshTable()
self.tableView.reloadData()
}
// CoreData Functions
func taskFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Costs")
let sortDescriptor = NSSortDescriptor(key: "costsDate", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
return fetchRequest
}
func getFetchedResultsController() -> NSFetchedResultsController {
fetchedResultsController = NSFetchedResultsController(fetchRequest: taskFetchRequest(), managedObjectContext: managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultsController
}
// NSFetchedResultsControllerDelegate
func controllerDidChangeContent(controller: NSFetchedResultsController) {
tableView.reloadData()
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
let thisCost = fetchedResultsController.objectAtIndexPath(indexPath) as Costs
managedObjectContext?.deleteObject(thisCost)
costsValues = getAccountCountSum()
refreshTable()
self.tableView.reloadData()
(UIApplication.sharedApplication().delegate as AppDelegate).saveContext()
}
// Sum count in all accouts
func getAccountCountSum() -> Int {
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let managedContext : NSManagedObjectContext = appDelegate.managedObjectContext!
var fetchRequest = NSFetchRequest(entityName: "Costs")
fetchRequest.returnsObjectsAsFaults = false
var results: NSArray = managedContext.executeFetchRequest(fetchRequest, error: nil)!
var accountsSum: Int = 0
for res in results {
var accountCount = res.valueForKey("costsValue") as Int
accountsSum += accountCount
}
self.sumLabel.text = String("\(costsValues) zł")
return accountsSum
}
func refreshTable() {
getAccountCountSum()
self.tableView.reloadData()
}
}
AddTableViewController
#IBAction func saveButtonTapped(sender: UIBarButtonItem) {
// CoreData Access
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var managedObjectContext = appDelegate.managedObjectContext
let entityDescription = NSEntityDescription.entityForName("Costs", inManagedObjectContext: managedObjectContext!)
let cost = Costs(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext!)
cost.costsName = cellThreeNoteTextField.text
cost.costsValue = (cellOnePriceTextField.text).toInt()!
cost.costsDate = datePicker.date
// Saving data
appDelegate.saveContext()
var request = NSFetchRequest(entityName: "Costs")
var error:NSError? = nil
var results:NSArray = managedObjectContext!.executeFetchRequest(request, error: &error)!
for res in results {
println(res)
}
delegate?.refreshTable()
self.navigationController?.popViewControllerAnimated(true)
}
Since you're using an NSFetchedResultsController, you create sections by passing a key on your managed objects to the sectionNameKeyPath argument. The sections property of the fetched results controller will then break up the results into sections based on the values of that key path in the fetched objects.
You'll also need to implement UITableView callbacks to get it to use the sections-- for example, sectionIndexTitlesForTableView and tableView:titleForHeaderInSection:. These are described in the NSFetchedResultsController documentation.

Resources