I currently have two managed objects for Core Data that has one-to-many relationship.
Goal
extension Goal {
@nonobjc public class func createFetchRequest() -> NSFetchRequest<Goal> {
return NSFetchRequest<Goal>(entityName: "Goal")
}
@NSManaged public var title: String
@NSManaged public var date: Date
@NSManaged public var progress: NSSet?
}
Progress
extension Progress {
@nonobjc public class func createFetchRequest() -> NSFetchRequest<Progress> {
return NSFetchRequest<Progress>(entityName: "Progress")
}
@NSManaged public var date: Date
@NSManaged public var comment: String?
@NSManaged public var goal: Goal
}
For every goal, you can have multiple Progress
objects. The problem is when I request a fetch for Progress
with a particular Goal
as the predicate, nothing is being returned. I have a suspicion that I'm not using the predicate properly.
This is how I request them.
- First, I fetch
Goal
for a table view controller:
var fetchedResultsController: NSFetchedResultsController<Goal>!
if fetchedResultsController == nil {
let request = Goal.createFetchRequest()
let sort = NSSortDescriptor(key: "date", ascending: false)
request.sortDescriptors = [sort]
request.fetchBatchSize = 20
fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: self.context, sectionNameKeyPath: "title", cacheName: nil)
fetchedResultsController.delegate = self
}
fetchedResultsController.fetchRequest.predicate = goalPredicate
do {
try fetchedResultsController.performFetch()
} catch {
print("Fetch failed")
}
- And pass the result to the next screen,
Detail
view controller:
if let vc = storyboard?.instantiateViewController(withIdentifier: "Detail") as? DetailViewController {
vc.goal = fetchedResultsController.object(at: indexPath)
navigationController?.pushViewController(vc, animated: true)
}
- Finally, I fetch
Progress
using theGoal
as the predicate fromDetail
view controller:
var goal: Goal!
let progressRequest = Progress.createFetchRequest()
progressRequest.predicate = NSPredicate(format: "goal == %@", goal)
if let progress = try? self.context.fetch(progressRequest) {
print("progress: \(progress)")
if progress.count > 0 {
fetchedResult = progress[0]
print("fetchedResult: \(fetchedResult)")
}
}
Goal
is being returned properly, but I get nothing back for Progress
. I've tried:
progressRequest.predicate = NSPredicate(format: "goal.title == %@", goal.title)
or
progressRequest.predicate = NSPredicate(format: "ANY goal == %@", goal)
but still the same result.
Following is how I set up the relationship:
// input for Progress from the user
let progress = Progress(context: self.context)
progress.date = Date()
progress.comment = commentTextView.text
// fetch the related Goal
var goalForProgress: Goal!
let goalRequest = Goal.createFetchRequest()
goalRequest.predicate = NSPredicate(format: "title == %@", titleLabel.text!)
if let goal = try? self.context.fetch(goalRequest) {
if goal.count > 0 {
goalForProgress = goal[0]
}
}
// establish the relationship between Goal and Progress
goalForProgress.progress.insert(progress)
// save
if self.context.hasChanges {
do {
try self.context.save()
} catch {
print("An error occurred while saving: \(error.localizedDescription)")
}
}
var goal: Goal!
declares the variable but it is not set – vadianvc.goal = fetchedResultsController.object(at: indexPath)
, and using it as the predicate. – KevvvDetailViewController
? And rather thantry?
catch the error. – vadianviewDidLoad()
. – Kevvv