核心数据关系、NSSet 和 ManagedObjectContext
Core Data relationship, NSSet & ManagedObjectContext
我想做什么
我正在构建一个演示应用程序以了解如何使用 Core Data。但我有一些问题:
NSManagedObjectContext
有比我现在的更简单的实现吗?
我不知道如何用 NSSet 完成代码
该应用只是 一个 table,其中包含 员工姓名、出生日期和每个 的 2 个任务列表.任务有多种状态(活动、完成等)。有一个项目按钮可通往另一个视图,您可以在其中输入姓名和任务,并将出生日期设置为当前日期。
我有 2 个实体(只用 EmployeeEntity
就可以完成吗?):
EmployeeEntity
具有属性 name
和 dateOfBirth
+ 与目的地 TaskEntity
的一对多 tasks
关系
TaskEntity
具有属性 name
并且反向关系 employee
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
类型变量。我看到其他人使用 Set
s。我试过 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
的代码很好,反之亦然。
我想做什么
我正在构建一个演示应用程序以了解如何使用 Core Data。但我有一些问题:
NSManagedObjectContext
有比我现在的更简单的实现吗?我不知道如何用 NSSet 完成代码
该应用只是 一个 table,其中包含 员工姓名、出生日期和每个 的 2 个任务列表.任务有多种状态(活动、完成等)。有一个项目按钮可通往另一个视图,您可以在其中输入姓名和任务,并将出生日期设置为当前日期。
我有 2 个实体(只用 EmployeeEntity
就可以完成吗?):
EmployeeEntity
具有属性name
和dateOfBirth
+ 与目的地TaskEntity
的一对多 TaskEntity
具有属性name
并且反向关系employee
tasks
关系
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
类型变量。我看到其他人使用 Set
s。我试过 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
的代码很好,反之亦然。