我正在构建一个演示应用程序,以了解如何使用Core Data。但我有一些问题:
NSManagedObjectContext
的实施方式是否比现有的更容易?
我不知道如何使用NSSet完成代码
该应用只是一个表,其中列出了员工的姓名,出生日期和每个的2个任务。任务具有多种状态(活动,完整等)。有一个项目按钮,指向另一个视图,您可以在其中输入名称和任务,并将出生日期设置为当前日期。
我有2个实体(可以只使用EmployeeEntity
吗?):
EmployeeEntity
包含name
和dateOfBirth
+与目标tasks
的一对多TaskEntity
关系TaskEntity
包含属性name
和反向关系employee
在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
}
}
}
然后表VC中的fetchedResultsController
:
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
}()
问题在于数据类型。首先,我不知道如何获得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)")
}
现在VC表中的cellForRowAtIndexPath
(我被困在这里):
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
我的猜测是我需要明确告诉它在TaskEntity
NSSet中只包含tasks
类型变量或类似的东西。我看到其他人使用Set
s。我尝试Set<TaskEntity>
并且没有错误,但我不知道如何调整代码,我将这些代码转换为数组。
答案 0 :(得分:3)
将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
考虑重命名Core Data实体及其属性。实际上,NSManagedObject
子类始终是一个实体,因此在名称中包含Entity
是多余的。或者taskName
中的属性TaskEntity
可能只是name
。在阅读代码时,您可以推断出name
属于Task
关于status
属性,您需要在Int32
实体中创建statusValue
属性Task
,以便将值存储在Core Data中。将枚举映射到Int32
的代码,反之亦然。