使用 CoreData 存储
Posted
技术标签:
【中文标题】使用 CoreData 存储【英文标题】:Storing with CoreData 【发布时间】:2015-07-29 21:34:35 【问题描述】:我的应用程序非常简单:我有一个 tableview 来存储食谱 *names,并且对于每个食谱名称,另一个 tableview 包含每个食谱的几个 *ingredients。
我已经设法用 CoreData 保存了名称和成分,但问题是:当我按下添加新配方名称并进入成分表视图区域时,为之前的配方保存的成分就在那里!如何清除表格视图以开始一个新的?
另外,我的表格视图不会立即更新,我必须关闭应用程序并再次打开它。我该如何解决?
注意:如果我的问题太难理解,我可以贴一些代码!提前谢谢大家=)
编辑
代码:
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)
和模型:
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
【问题讨论】:
【参考方案1】:大纲:
-
你需要修改你的模型:目前每个
Details
对象只能有一个Ingredients
。我怀疑你需要这种关系“对许多人”,这样一个食谱就可以有很多成分。
您需要向您的IngredientListViewController
添加一个变量(Details?
类型)。这将代表所选配方。 (例如var chosenRecipe : Details?
)
在fetchIngredient
中,您需要为提取添加一个谓词,以将结果限制为所选配方。例如。 fetch.predicate = NSPredicate(format:"ANY relationship == %@", chosenRecipe)
在 segue 到这个 VC 之前,您需要设置 chosenRecipe
(可能在 prepareForSegue 中,或者在前面的表视图中的 didSelectRowAtIndexPath 中)。
要让您的电视自动更新,请使用fetchedResultsController
委托方法。 (你实现了这些吗?)
【讨论】:
我设法让我的表格视图工作,但我仍然不知道如何清除列表,因为当我添加新项目时,旧项目不会显示。完成后我会告诉你的! 我不知道如何设置CoreData在我开始一个新项目时清除所有数据:(你能教我吗? @NicholasPiccoli 能否再解释一下残差问题? 想象一下:我有一个包含多个项目的 tableview,每个项目都有自己的 tableview 和自己的项目。例如。当我添加第一个食谱并添加其成分时,一切正常,但是当我输入第二个食谱并尝试添加其新成分时,预览食谱的成分就在那里!等等。他们积累。我想学习每次添加新食谱时如何清除配料表。 注意:我必须重置它,但将其保存在内存中,因为稍后当我通过 didSelecRowAtIndexPath 访问添加的每个配方的行时,将显示一个屏幕,其中包含每个配方的详细信息。以上是关于使用 CoreData 存储的主要内容,如果未能解决你的问题,请参考以下文章