核心数据关系、NSSet 和 ManagedObjectContext

Core Data relationship, NSSet & ManagedObjectContext

我想做什么

我正在构建一个演示应用程序以了解如何使用 Core Data。但我有一些问题:

  1. NSManagedObjectContext 有比我现在的更简单的实现吗?

  2. 我不知道如何用 NSSet 完成代码

该应用只是 一个 table,其中包含 员工姓名、出生日期和每个 的 2 个任务列表.任务有多种状态(活动、完成等)。有一个项目按钮可通往另一个视图,您可以在其中输入姓名和任务,并将出生日期设置为当前日期。

我有 2 个实体(只用 EmployeeEntity 就可以完成吗?):

1。托管对象上下文实现(有 shorter/easier/better 吗?)

AppDelegate(...didFinishLaunchingWithOptions...) 中,我为第一个屏幕设置 managedObjectContext

// Fetch Main Storyboard
    let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)

    // Instantiate Root Navigation Controller
    let rootNavigationController = mainStoryboard.instantiateViewControllerWithIdentifier("StoryboardIDRootNavigationController") as! UINavigationController

    // Configure View Controller
    let viewController = rootNavigationController.topViewController as? TableTVC

    if let viewController = viewController {
        viewController.managedObjectContext = self.managedObjectContext
    }

    // Configure Window
    window?.rootViewController = rootNavigationController

    return true

然后在 prepareForSegue 中传递它(目标 VC 中有一个 managedObjectContext 变量):

if segue.identifier == "idTableToNew" {
        if let navVC = segue.destinationViewController as? UINavigationController {
            if let newVC = navVC.topViewController as? NewVC {
                newVC.managedObjectContext = managedObjectContext
            }
        }
    }

然后table中的fetchedResultsController VC:

lazy var frc: NSFetchedResultsController = {
    // Initialize Fetch Request
    let fetchRequest = NSFetchRequest(entityName: "EmployeeEntity")

    // Configure Predicate
    // Need to make changes because I only want today's date
    let predicate = NSPredicate(format: "%K == %@", "dateOfBirth", NSDate())
    fetchRequest.predicate = predicate

    // Initialize Fetched Results Controller
    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

    // Configure Fetched Results Controller
    fetchedResultsController.delegate = self

    return fetchedResultsController
}()

2。我卡在的代码

问题出在数据类型上。首先,我不知道如何获得 tasks' 状态。其次,我不确定这是否是最好的方法。

下面是TasksEntity.swift代码(导入和生成的注释除外):

enum TaskStatus: Int32 {
    case Complete, Incomplete, Active, Inactive
}

class TaskEntity: NSManagedObject {

    @NSManaged private var statusValue: Int32

    var status: TaskStatus {
        get {
            return TaskStatus(rawValue: self.statusValue)!
        }
        set {
            self.statusValue = newValue.rawValue
        }
    }
}

保存数据(按下项目按钮时的操作):

    let name = nameField.text
    let task1Text = task1Field.text
    let task2Text = task2Field.text

    // Create Entities
    let employee = NSEntityDescription.entityForName("EmployeeEntity", inManagedObjectContext: managedObjectContext)
    let task = NSEntityDescription.entityForName("TaskEntity", inManagedObjectContext: managedObjectContext)

    // Initialize Records
    let employeeRecord = EmployeeEntity(entity: employee!, insertIntoManagedObjectContext: managedObjectContext)
    let taskRecord = TaskEntity(entity: task!, insertIntoManagedObjectContext: managedObjectContext)
    let taskRecord2 = TaskEntity(entity: task!, insertIntoManagedObjectContext: managedObjectContext)

    // Populate Records
    employeeRecord.name = name
    employeeRecord.dateOfBirth = NSDate()
    taskRecord.taskName = task1Text
    taskRecord.status = TaskStatus.Inactive // Apparently no errors so it might work
    taskRecord2.taskName = task2Text
    taskRecord2.status = TaskStatus.Incomplete
    let taskArray = employeeRecord.mutableArrayValueForKey("tasks")
    taskArray.addObject(taskRecord)
    taskArray.addObject(taskRecord2)

    // Save MOC
    do {
        try managedObjectContext.save()
    } catch {
        let saveError = error as NSError
        print("\(saveError), \(saveError.userInfo)")
    }

现在 cellForRowAtIndexPath 在 table VC 中(我卡在这里了):

let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! EmployeeTVCell

    // Fetch Record
    let employeeRecord = frc.objectAtIndexPath(indexPath) as! EmployeeEntity

    // Update Cell
    if let name = employeeRecord.name {
        cell.nameLabel.text = name
    }

    cell.dateLabel.text = String(employeeRecord.dateOfBirth)

    if let tasksArray = employeeRecord.tasks?.mutableArrayValueForKey("tasks") {
        if tasksArray.count != 0 {
            cell.task1Label.text = tasksArray[0] as? String
            cell.task1Label.text = tasksArray[1] as? String
            print(tasksArray[0].status)

            // I think that tasksArray[index] won't work but it's what I want to achieve
        }
    }

    return cell

照片和想法

我的猜测是我需要明确地告诉它在 tasks NSSet 或类似的东西中只包含 TaskEntity 类型变量。我看到其他人使用 Sets。我试过 Set<TaskEntity> 没有错误,但我不知道如何调整将集合转换为数组的代码。

Set 对象的成员作为数组获取的常用方法是方法 allObjects,但除此之外你不能将 TaskEntity 对象转换为 String.

...
if let tasksArray = employeeRecord.tasks?.allObjects as? [TaskEntity] where !tasksArray.isEmpty {
    cell.task1Label.text = tasksArray[0].taskName
    cell.task1Label.text = tasksArray[1].taskName // or is it cell.task2Label ??
    print(tasksArray[0].status)
}

return cell

考虑重命名核心数据实体及其属性。实际上 NSManagedObject 子类始终代表一个实体,因此在名称中包含 Entity 是多余的。或者 TaskEntity 中的属性 taskName 可能只是 name。在阅读代码时,您可以推断 name 属于 Task

关于 status 属性 您需要在 Task 实体中创建一个 Int32 属性 statusValue 以将值存储在核心数据中。将枚举映射到 Int32 的代码很好,反之亦然。