swift 中的核心数据一对多关系
Core data one to many relationship in swift
几天来我一直在寻找如何处理一对多关系的方法。
但是我想不通。
我正在开发一个存储科目成绩的应用程序。所以一个科目与成绩有一对多的关系。当前所有数据都存储在一个数组中。
var vakken: [(naam:String, voorkeurGemiddelde:Double, wegingGemiddelde:Double, cijfer:[Double], weging:[Double], gemiddelde:Double)] = []
其中 [Double] 的 - Cijfer 和 weging - 是等级的属性。
我目前有以下保存数据的方法:
let context = AppDelegate().managedObjectContext
// Create subject
let entitySubject = NSEntityDescription.entityForName("Subject", inManagedObjectContext: context)
let Subject = NSManagedObject(entity: entitySubject!, insertIntoManagedObjectContext: context)
// Populate subject
Subject.setValue(vakken.last!.naam, forKey: "name")
Subject.setValue(vakken.last!.voorkeurGemiddelde, forKey: "voorkeurGemiddelde")
Subject.setValue(vakken.last!.wegingGemiddelde, forKey: "wegingNP")
Subject.setValue(vakken.last!.gemiddelde, forKey: "gemiddelde")
for var j = 0; j < vakken.last!.cijfer.count-1; j++ {
let Grade = NSEntityDescription.insertNewObjectForEntityForName("Grade", inManagedObjectContext: context)
Grade.setValue(vakken.last!.cijfer[j], forKey: "cijfer")
Grade.setValue(vakken.last!.weging[j], forKey: "weging")
Subject.setValue(NSSet(object: Grade), forKey: "grade")
}
do{
try context.save()
}catch{
print("error")
}
我正在使用 tableView 中的数据。
我在一些教程中看到使用:var vakken = [NSManagedObject]()
然后在表格视图中使用它。
1。但这是否也适用于我的模型,我应该使用它吗?
我首先想到的是在应用程序终止时只保存数据,所以我会在应用程序委托中包含代码,然后在应用程序启动时检索它。
2。但是我如何将数组获取到 appdelegate,这会很聪明吗?
为了获取数据,我有这个:
let fetchRequest = NSFetchRequest(entityName: "Subject")
// // Add Sort Descriptor
// let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
// fetchRequest.sortDescriptors = [sortDescriptor]
let context = Appdelegate().managedObjectContext
// Execute Fetch Request
do {
let result = try context.executeFetchRequest(fetchRequest)
print(result)
} catch {
let fetchError = error as NSError
print(fetchError)
}
3。但是我如何从结果中得到我的数组,或者如果我使用 NSManagedObject 我如何引用属性,尤其是成绩。
我还按名称对数组进行排序,可以是 A-Z 或 Z-A,我按平均值排序,可以是 10-1 或 1-10。我有在我的数组中对其进行排序的代码。
4。但是我不知道如何用核心数据对它进行排序。
我还看过一个教程,他们为 属性制作了 class。
所以我自己做了一个:
import UIKit
import CoreData
import Foundation
class Subject: NSManagedObject {
@NSManaged var gemiddelde: Double
@NSManaged var name: String
@NSManaged var voorkeurGemiddelde: Double
@NSManaged var wegingNP: Double
@NSManaged var Grades: NSSet
}
class Grade: NSManagedObject {
@NSManaged var cijfer: Double
@NSManaged var weging: Double
@NSManaged var subject: Subject
}
extension Subject {
func addTagObject(value:Grade) {
let items = self.mutableSetValueForKey("grade");
items.addObject(value)
}
func removeTagObject(value:Grade) {
let items = self.mutableSetValueForKey("grade");
items.removeObject(value)
}
}
5.但是我不知道我是否需要它,也不知道如何使用它?
如果您有任何建议、技巧、好的教程或知道其中一个问题。
您的帮助将不胜感激。
如果您需要更多信息,请告诉我。 :)
更新:
我有这个代码来获取主题的对象 被点击了。
if let indexPath = self.tableView.indexPathForSelectedRow {
let object = self.fetchedResultsController.objectAtIndexPath(indexPath)
let controller = segue.destinationViewController as! VakTableViewController
controller.vak = object as! Subject
}
这是接收端的代码:
var vak: Subject! {
didSet {
// Update the view.
cijfers = vak.valueForKeyPath("grades.cijfer")!.allObjects as! [Double]
wegingen = vak.valueForKeyPath("grades.weging")!.allObjects as! [Double]
self.tableView.reloadData()
}
}
var cijfers: Array<Double>!
var wegingen: Array<Double>!
6.但是我怎样才能删除成绩?
我试过这个:
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
if cijfers.count != 1 {
let entityGrade = NSEntityDescription.entityForName("Grade", inManagedObjectContext: mangedobjectcontext)
let grade = Grade(entity: entityGrade!, insertIntoManagedObjectContext: mangedobjectcontext)
grade.cijfer = cijfers[indexPath.row]
grade.weging = wegingen[indexPath.row]
vak.removeGradeObject(grade)
do{
try mangedobjectcontext.save()
}catch{
print("error")
}
cijfers.removeAtIndex(indexPath.row)
wegingen.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
print(vak.valueForKeyPath("grades.cijfer")?.allObjects)
}
}
}
但这行不通。
7.当我只更改自己的变量时,如何将 vak(subject) 保存到上下文中?
像这样:vak.gemiddelde = newgemiddelde
直接回答您的问题:
I am using the data in a tableView. I have seen in some tutorials that the use: var vakken = [NSManagedObject]()
and then use it in a tableview.
Is this also possible with the model I have, and should I use it
当然可以,但使用 NSFetchedResultsController
可能会更好(参见 Apple Docs)。这是专门设计的,可以轻松地使用 Core-Data 中的数据填充 tableView。
I first thought was to just save the data when the app terminates, so I would have the code in the app delegate, and then just retrive it when the app starts. How would I get the array to the appdelegate and would this be smart?
我不会 populate/save App Delegate 中的数组。有些人遵循 Apple 的模板项目,在 App Delegate 中构建 CoreData 堆栈;其他人有一个单独的 class 他们实例化来管理堆栈。从您的代码来看,它目前使用前者。然后,您的视图控制器可以使用以下方法从 App Delegate 获取 NSManagedObjectContext
:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context = appDelegate.managedObjectContext
(正如 beyowulf 指出的那样,您不应使用 AppDelegate().managedObjectContext
,因为它会创建一个新实例,而不是引用现有实例)。一旦他们有了上下文,您的视图控制器就可以获取他们需要的数据、添加或更新现有记录等。
But how would I get from the result my array back or if I use NSManagedObject how can I refer to the attributes and in most particular the grades.
result
是NSManagedObjects
的数组。您可以使用 valueForKey
获取属性值,"read" 相当于 setValue:(_, forKey:)
:
let firstObject = result[0]
let firstObjectName = firstObject.valueForKey("name")
同理,可以通过以下方式获得成绩:
let firstObjectGrades = firstObject.valueForKey("grades")
不过,还有更好的方法:请参阅下面的最后一个问题。
I also sort my array by name which can be A-Z or Z-A, and I sort by average which can be 10-1 or 1-10. I have the code to sort it in my array. But I don't know how to sort this with core data.
取数据时最容易排序。为此,请为提取指定 NSSortDescriptor
(请参阅 Apple Docs):
let fetchRequest = NSFetchRequest(entityName: "Subject")
fetchRequest.sortDescriptors = [NSSortDescriptor(key:"name", ascending:true)
I have also seen a tutorial where they made a class for the attributes. I don't know if I need it nor how to use it?
是的,使用它。这将使生活变得更加轻松。与其编写自己的 class 定义,不如在数据模型编辑器中使用 Xcode 菜单选项 "Create NSManagedObject subclasses"。它将为您创建 class 代码,并将每个实体设置为使用相应的 class。 (如果您希望坚持使用自己的代码,则需要在数据模型编辑器中为每个实体修改 "class")。
一旦你正确定义了子classes,你就可以使用点符号来引用属性和关系,而不需要使用valueForKey
和setValueForKey
:
所以:
let Subject = NSManagedObject(entity: entitySubject!, insertIntoManagedObjectContext: context)
将变为:
let subject = Subject(entity: entitySubject!, insertIntoManagedObjectContext: context)
(注意,变量应以小写开头 - 类 实体名称应以大写开头)。
Grade.setValue(vakken.last!.cijfer[j], forKey: "cijfer")
变为:
grade.cijfer = vakken.last!.cijfer[j]
和
let firstObjectGrades = firstObject.valueForKey("grades")
变为:
let firstObjectGrades = firstObject.grades
此外,addTagObject
和 removeTagObject
函数将使管理一对多关系变得更加容易。您的代码目前有:
Subject.setValue(NSSet(object: Grade), forKey: "grade")
这将用 Grade
对象 替换 任何现有的 Subject
成绩:它不会将其添加到现有成绩中。事实上,对于一对多关系,管理反向(一对一)关系要容易得多:
grade.subject = subject
CoreData 会自动为您处理反向(对多)关系。
How can i delete one of the grades?
首先,不要为每个 Grades
属性构建单独的数组:只为 Grades
:
创建一个数组
var vak: Subject! {
didSet {
// Update the view.
grades = vak.grades.allObjects as! [Grade]
self.tableView.reloadData()
}
}
var grades: Array<Grade>!
您可以在需要时轻松获取属性。例如,在您的 cellForRowAtIndexPath
中,您可能有这样的内容:
let grade = grades[indexPath.row]
let cijfer = grade.cijfer
let weging = grade.weging
// populate cell labels etc using "cijfer" and "waging"
然后您的 commitEditingStyle
可以轻松找到正在删除的 Grade
,并进行相应处理:
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let grade = grades[indexPath.row]
// either remove the Grade from your Subject (which leaves
// the Grade "orphaned"):
grade.subject = nil
// or (probably better) completely delete the grade:
managedobjectcontext.deleteObject(grade)
// then remove it from the "grades" array:
grades.removeAtIndex(indexPath.row)
// and finally delete the corresponding table view row
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
// wrap up by saving the changes to the context:
do{
try mangedobjectcontext.save()
}catch{
print("error")
}
}
}
How can i save the vak(subject) to the context when i just change one of the variable?
无论何时保存上下文,它都会将所有更改保存到向其注册的任何对象(插入其中或使用它获取)。因此,即使您所做的唯一更改是修改一个 Subject
的一个属性,也只需在上下文中调用 save()
。
几天来我一直在寻找如何处理一对多关系的方法。 但是我想不通。
我正在开发一个存储科目成绩的应用程序。所以一个科目与成绩有一对多的关系。当前所有数据都存储在一个数组中。
var vakken: [(naam:String, voorkeurGemiddelde:Double, wegingGemiddelde:Double, cijfer:[Double], weging:[Double], gemiddelde:Double)] = []
其中 [Double] 的 - Cijfer 和 weging - 是等级的属性。
我目前有以下保存数据的方法:
let context = AppDelegate().managedObjectContext
// Create subject
let entitySubject = NSEntityDescription.entityForName("Subject", inManagedObjectContext: context)
let Subject = NSManagedObject(entity: entitySubject!, insertIntoManagedObjectContext: context)
// Populate subject
Subject.setValue(vakken.last!.naam, forKey: "name")
Subject.setValue(vakken.last!.voorkeurGemiddelde, forKey: "voorkeurGemiddelde")
Subject.setValue(vakken.last!.wegingGemiddelde, forKey: "wegingNP")
Subject.setValue(vakken.last!.gemiddelde, forKey: "gemiddelde")
for var j = 0; j < vakken.last!.cijfer.count-1; j++ {
let Grade = NSEntityDescription.insertNewObjectForEntityForName("Grade", inManagedObjectContext: context)
Grade.setValue(vakken.last!.cijfer[j], forKey: "cijfer")
Grade.setValue(vakken.last!.weging[j], forKey: "weging")
Subject.setValue(NSSet(object: Grade), forKey: "grade")
}
do{
try context.save()
}catch{
print("error")
}
我正在使用 tableView 中的数据。
我在一些教程中看到使用:var vakken = [NSManagedObject]()
然后在表格视图中使用它。
1。但这是否也适用于我的模型,我应该使用它吗?
我首先想到的是在应用程序终止时只保存数据,所以我会在应用程序委托中包含代码,然后在应用程序启动时检索它。
2。但是我如何将数组获取到 appdelegate,这会很聪明吗?
为了获取数据,我有这个:
let fetchRequest = NSFetchRequest(entityName: "Subject")
// // Add Sort Descriptor
// let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
// fetchRequest.sortDescriptors = [sortDescriptor]
let context = Appdelegate().managedObjectContext
// Execute Fetch Request
do {
let result = try context.executeFetchRequest(fetchRequest)
print(result)
} catch {
let fetchError = error as NSError
print(fetchError)
}
3。但是我如何从结果中得到我的数组,或者如果我使用 NSManagedObject 我如何引用属性,尤其是成绩。
我还按名称对数组进行排序,可以是 A-Z 或 Z-A,我按平均值排序,可以是 10-1 或 1-10。我有在我的数组中对其进行排序的代码。
4。但是我不知道如何用核心数据对它进行排序。
我还看过一个教程,他们为
import UIKit
import CoreData
import Foundation
class Subject: NSManagedObject {
@NSManaged var gemiddelde: Double
@NSManaged var name: String
@NSManaged var voorkeurGemiddelde: Double
@NSManaged var wegingNP: Double
@NSManaged var Grades: NSSet
}
class Grade: NSManagedObject {
@NSManaged var cijfer: Double
@NSManaged var weging: Double
@NSManaged var subject: Subject
}
extension Subject {
func addTagObject(value:Grade) {
let items = self.mutableSetValueForKey("grade");
items.addObject(value)
}
func removeTagObject(value:Grade) {
let items = self.mutableSetValueForKey("grade");
items.removeObject(value)
}
}
5.但是我不知道我是否需要它,也不知道如何使用它?
如果您有任何建议、技巧、好的教程或知道其中一个问题。 您的帮助将不胜感激。
如果您需要更多信息,请告诉我。 :)
更新:
我有这个代码来获取主题的对象 被点击了。
if let indexPath = self.tableView.indexPathForSelectedRow {
let object = self.fetchedResultsController.objectAtIndexPath(indexPath)
let controller = segue.destinationViewController as! VakTableViewController
controller.vak = object as! Subject
}
这是接收端的代码:
var vak: Subject! {
didSet {
// Update the view.
cijfers = vak.valueForKeyPath("grades.cijfer")!.allObjects as! [Double]
wegingen = vak.valueForKeyPath("grades.weging")!.allObjects as! [Double]
self.tableView.reloadData()
}
}
var cijfers: Array<Double>!
var wegingen: Array<Double>!
6.但是我怎样才能删除成绩?
我试过这个:
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
if cijfers.count != 1 {
let entityGrade = NSEntityDescription.entityForName("Grade", inManagedObjectContext: mangedobjectcontext)
let grade = Grade(entity: entityGrade!, insertIntoManagedObjectContext: mangedobjectcontext)
grade.cijfer = cijfers[indexPath.row]
grade.weging = wegingen[indexPath.row]
vak.removeGradeObject(grade)
do{
try mangedobjectcontext.save()
}catch{
print("error")
}
cijfers.removeAtIndex(indexPath.row)
wegingen.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
print(vak.valueForKeyPath("grades.cijfer")?.allObjects)
}
}
}
但这行不通。
7.当我只更改自己的变量时,如何将 vak(subject) 保存到上下文中?
像这样:vak.gemiddelde = newgemiddelde
直接回答您的问题:
I am using the data in a tableView. I have seen in some tutorials that the use:
var vakken = [NSManagedObject]()
and then use it in a tableview. Is this also possible with the model I have, and should I use it
当然可以,但使用 NSFetchedResultsController
可能会更好(参见 Apple Docs)。这是专门设计的,可以轻松地使用 Core-Data 中的数据填充 tableView。
I first thought was to just save the data when the app terminates, so I would have the code in the app delegate, and then just retrive it when the app starts. How would I get the array to the appdelegate and would this be smart?
我不会 populate/save App Delegate 中的数组。有些人遵循 Apple 的模板项目,在 App Delegate 中构建 CoreData 堆栈;其他人有一个单独的 class 他们实例化来管理堆栈。从您的代码来看,它目前使用前者。然后,您的视图控制器可以使用以下方法从 App Delegate 获取 NSManagedObjectContext
:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context = appDelegate.managedObjectContext
(正如 beyowulf 指出的那样,您不应使用 AppDelegate().managedObjectContext
,因为它会创建一个新实例,而不是引用现有实例)。一旦他们有了上下文,您的视图控制器就可以获取他们需要的数据、添加或更新现有记录等。
But how would I get from the result my array back or if I use NSManagedObject how can I refer to the attributes and in most particular the grades.
result
是NSManagedObjects
的数组。您可以使用 valueForKey
获取属性值,"read" 相当于 setValue:(_, forKey:)
:
let firstObject = result[0]
let firstObjectName = firstObject.valueForKey("name")
同理,可以通过以下方式获得成绩:
let firstObjectGrades = firstObject.valueForKey("grades")
不过,还有更好的方法:请参阅下面的最后一个问题。
I also sort my array by name which can be A-Z or Z-A, and I sort by average which can be 10-1 or 1-10. I have the code to sort it in my array. But I don't know how to sort this with core data.
取数据时最容易排序。为此,请为提取指定 NSSortDescriptor
(请参阅 Apple Docs):
let fetchRequest = NSFetchRequest(entityName: "Subject")
fetchRequest.sortDescriptors = [NSSortDescriptor(key:"name", ascending:true)
I have also seen a tutorial where they made a class for the attributes. I don't know if I need it nor how to use it?
是的,使用它。这将使生活变得更加轻松。与其编写自己的 class 定义,不如在数据模型编辑器中使用 Xcode 菜单选项 "Create NSManagedObject subclasses"。它将为您创建 class 代码,并将每个实体设置为使用相应的 class。 (如果您希望坚持使用自己的代码,则需要在数据模型编辑器中为每个实体修改 "class")。
一旦你正确定义了子classes,你就可以使用点符号来引用属性和关系,而不需要使用valueForKey
和setValueForKey
:
所以:
let Subject = NSManagedObject(entity: entitySubject!, insertIntoManagedObjectContext: context)
将变为:
let subject = Subject(entity: entitySubject!, insertIntoManagedObjectContext: context)
(注意,变量应以小写开头 - 类 实体名称应以大写开头)。
Grade.setValue(vakken.last!.cijfer[j], forKey: "cijfer")
变为:
grade.cijfer = vakken.last!.cijfer[j]
和
let firstObjectGrades = firstObject.valueForKey("grades")
变为:
let firstObjectGrades = firstObject.grades
此外,addTagObject
和 removeTagObject
函数将使管理一对多关系变得更加容易。您的代码目前有:
Subject.setValue(NSSet(object: Grade), forKey: "grade")
这将用 Grade
对象 替换 任何现有的 Subject
成绩:它不会将其添加到现有成绩中。事实上,对于一对多关系,管理反向(一对一)关系要容易得多:
grade.subject = subject
CoreData 会自动为您处理反向(对多)关系。
How can i delete one of the grades?
首先,不要为每个 Grades
属性构建单独的数组:只为 Grades
:
var vak: Subject! {
didSet {
// Update the view.
grades = vak.grades.allObjects as! [Grade]
self.tableView.reloadData()
}
}
var grades: Array<Grade>!
您可以在需要时轻松获取属性。例如,在您的 cellForRowAtIndexPath
中,您可能有这样的内容:
let grade = grades[indexPath.row]
let cijfer = grade.cijfer
let weging = grade.weging
// populate cell labels etc using "cijfer" and "waging"
然后您的 commitEditingStyle
可以轻松找到正在删除的 Grade
,并进行相应处理:
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let grade = grades[indexPath.row]
// either remove the Grade from your Subject (which leaves
// the Grade "orphaned"):
grade.subject = nil
// or (probably better) completely delete the grade:
managedobjectcontext.deleteObject(grade)
// then remove it from the "grades" array:
grades.removeAtIndex(indexPath.row)
// and finally delete the corresponding table view row
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
// wrap up by saving the changes to the context:
do{
try mangedobjectcontext.save()
}catch{
print("error")
}
}
}
How can i save the vak(subject) to the context when i just change one of the variable?
无论何时保存上下文,它都会将所有更改保存到向其注册的任何对象(插入其中或使用它获取)。因此,即使您所做的唯一更改是修改一个 Subject
的一个属性,也只需在上下文中调用 save()
。