【问题标题】:Core data one to many relationship in swiftswift中的核心数据一对多关系
【发布时间】:2016-05-24 04:25:03
【问题描述】:

我一直在寻找如何处理一对多关系的问题。 但我想不通。

我正在开发一个存储学科成绩的应用程序。所以一门学科与成绩有一对多的关系。当前所有数据都存储在一个数组中。

var vakken: [(naam:String, voorkeurGemiddelde:Double, wegingGemiddelde:Double, cijfer:[Double], weging:[Double], gemiddelde:Double)] = []
[Double]'s - 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](),然后在 tableview 中使用它。
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。但我不知道如何用核心数据对其进行排序。

我还看过一个教程,他们为link 属性创建了一个类。 所以我自己做了一个:

    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

【问题讨论】:

  • 我不认为您打算使用 AppDelegate(),因为它会初始化您的 AppDelegate 的新实例,而是我认为您的意思是“让 appDelegate = UIApplication.sharedApplication().delegate 为! AppDelegate',因为这将获取应用程序 AppDelegate 的当前实例。
  • Appdelegate() 是一个返回 appdelegate 的函数。所以不用担心。

标签: swift core-data relationship one-to-many


【解决方案1】:

直接解决您的问题:

我正在使用 tableView 中的数据。我在一些教程中看到使用:var vakken = [NSManagedObject](),然后在 tableview 中使用它。 我的模型也可以吗?我应该使用它

当然可以,但最好使用NSFetchedResultsController(请参阅Apple Docs)。这是专门设计用于使用来自 Core-Data 的数据轻松填充 tableView。

我最初的想法是在应用程序终止时保存数据,所以我会在应用程序委托中保存代码,然后在应用程序启动时检索它。 如何将数组传递给 appdelegate,这会很聪明吗?

我不会在 App Delegate 中填充/保存数组。有些人遵循苹果的模板项目,在 App Delegate 中构建 CoreData 堆栈;其他人有一个单独的类,他们实例化来管理堆栈。从您的代码的外观来看,它目前使用的是前者。然后,您的视图控制器可以使用以下方法从 App Delegate 获取 NSManagedObjectContext

let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context = appDelegate.managedObjectContext

(正如 beyowulf 指出的那样,您不应该使用AppDelegate().managedObjectContext,因为它会创建一个新实例,而不是引用现有实例)。一旦有了上下文,您的视图控制器就可以获取他们需要的数据、添加或更新现有记录等。

但是我如何从结果中得到我的数组,或者如果我使用 NSManagedObject,我如何引用属性,尤其是成绩。

resultNSManagedObjects 的数组。您可以使用valueForKey 获取属性值,setValue:(_, forKey:) 的“读取”等效项:

let firstObject = result[0]
let firstObjectName = firstObject.valueForKey("name")

同样可以通过以下方式获得成绩:

let firstObjectGrades = firstObject.valueForKey("grades")

不过还有更好的方法:请参阅下面的最后一个问题。

我还按名称对数组进行排序,可以是 A-Z 或 Z-A,我按平均值排序,可以是 10-1 或 1-10。我有代码可以在我的数组中对其进行排序。 但我不知道如何使用核心数据对其进行排序。

获取数据时最容易对数据进行排序。为此,请指定一个NSSortDescriptor(请参阅Apple Docs)进行提取:

let fetchRequest = NSFetchRequest(entityName: "Subject")
fetchRequest.sortDescriptors = [NSSortDescriptor(key:"name", ascending:true)

我还看过一个教程,他们为属性创建了一个类。 不知是否需要,不知如何使用?

是的,使用它。这将使生活变得更加轻松。与其编写自己的类定义,不如在数据模型编辑器中使用 Xcode 菜单选项“创建 NSManagedObject 子类”。它将为您创建类代码,并将每个实体设置为使用相应的类。 (如果您希望坚持使用自己的代码,则需要在数据模型编辑器中修改每个实体的“类”)。

一旦正确定义了子类,就可以使用点符号来引用属性和关系,而无需使用valueForKeysetValueForKey

所以:

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

此外,addTagObjectremoveTagObject 函数将使管理对多关系变得更加容易。您的代码目前有:

Subject.setValue(NSSet(object: Grade), forKey: "grade")

这会将Subject 的任何现有成绩替换Grade 对象:它不会将其添加到现有成绩中。事实上,对于一对多关系,管理反向(一对一)关系要容易得多:

grade.subject = subject

CoreData 会自动为您处理反向(对多)关系。

如何删除其中一个成绩?

首先,不要为每个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")
        }
    }
}

当我只更改其中一个变量时,如何将 vak(subject) 保存到上下文中?

每当您保存上下文时,它都会将所有更改保存到使用它注册的任何对象(插入其中或使用它获取)。因此,即使您所做的唯一更改是修改 Subject 的一个属性,也只需在上下文中调用 save()

【讨论】:

  • 是否有可能因为 vak.grades 似乎只是关系而获得一个学科的成绩的 cijfer?
  • 当然 - 恢复使用valueForKeyPath:像这样let cijfers = subject.valueForKeyPath("grades.cijfer")
  • 但是由于 cijfers[0] 崩溃,我将如何获得个人号码
  • cijfers 是一个 NSSet,所以不能使用索引。使用let cijfers = subject.valueForKeyPath("grades.cijfer").allObjects() 将其转换为数组,然后您可以使用索引来获取各个值。
  • @Cing 更新了答案。
猜你喜欢
  • 2016-09-08
  • 2014-08-13
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
  • 1970-01-01
  • 1970-01-01
  • 2015-04-04
  • 1970-01-01
相关资源
最近更新 更多