Reputation: 5003
I have read here that the way to fetch multiple entities with 1 NSFetchedResultsController is to use a parent child inheritance model. I have such a model:
https://i.sstatic.net/Cq1ZB.jpg
As you can see, TextPost,VideoPost, and ImagePost all have Skill as a parent entity. I am trying to make a single collectionView for which all three children show up. I am a little confused as to how to set the delegate methods though...
Here is the code for the view controller
class Timeline2ViewController: UIViewController {
@IBOutlet var postsCollectionView: UICollectionView!
var skillName: String?
fileprivate lazy var skillFetchedResultsController: NSFetchedResultsController<Skill> = {
let appDelegate =
UIApplication.shared.delegate as? AppDelegate
let managedContext =
appDelegate?.persistentContainer.viewContext
let request: NSFetchRequest<Skill> = NSFetchRequest(entityName: "Skill")
request.predicate = NSPredicate(format: "name == %@", self.skillName!)
let timeSort = NSSortDescriptor(key: "timeStamp", ascending: true)
request.sortDescriptors = [timeSort]
let skillFetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: managedContext!, sectionNameKeyPath: nil, cacheName: nil)
return skillFetchedResultsController
}()
override func viewDidLoad() {
super.viewDidLoad()
do {
try skillFetchedResultsController.performFetch()
} catch let error as NSError {
print("SkillFetchError")
}
}
}
extension Timeline2ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
guard let sectionInfo = skillFetchedResultsController.sections?[section] else { return 0 }
return sectionInfo.numberOfObjects
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = postsCollectionView.dequeueReusableCell(withReuseIdentifier: "pcell", for: indexPath) as? PostViewCell else { return fatalError("unexpected Index Path")
}
let post = skillFetchedResultsController[indexPath.row] /* This is the line im not sure about
cell.background
return cell
}
}
Since only 1 entity is actually, returned, I am not sure how to access an element at a specific index path. For instance skillFetchedResultsController[indexPath.row] would I think only have 1 entity - the skill itself. I really want to be accessing its children. Do I have to somehow subclass skillFetchedResultsController and return only the children Im interested in?
Edit: with @pbasdf suggestions - I have this model:
Now when I create an entity like so:
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let textPost = NSEntityDescription.insertNewObject(forEntityName: "TextPost", into: managedContext) as! TextPost
textPost.text = "test text post"
try! managedContext.save()
and I setup my fetched results controller to look at "Post2" like so:
fileprivate lazy var skillFetchedResultsController: NSFetchedResultsController<Post2> = {
let appDelegate =
UIApplication.shared.delegate as? AppDelegate
let managedContext =
appDelegate?.persistentContainer.viewContext
let request: NSFetchRequest<Post2> = NSFetchRequest(entityName: "Post2")
// request.predicate = NSPredicate(format: "skill = %@", self.skill!)
let timeSort = NSSortDescriptor(key: "timeStamp", ascending: true)
request.sortDescriptors = [timeSort]
let skillFetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: managedContext!, sectionNameKeyPath: nil, cacheName: nil)
return skillFetchedResultsController
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
do {
try skillFetchedResultsController.performFetch()
} catch _ as NSError {
print("SkillFetchError")
}
}
I see no returned results in:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
guard let sectionInfo = skillFetchedResultsController.sections?[section] else { return 0 }
return sectionInfo.numberOfObjects
}
Do I somehow need to link the two? Like create the Post object and the TextPost object at the same time? When I try and fetch TextPost objects directly it works.
Upvotes: 1
Views: 84
Reputation: 21536
I think the problem lies in your model. You should create a Post
entity, and make it the parent entity of TextPost
, VideoPost
, and ImagePost
. If your subentities have any attributes in common, move them from the subentities to the Post
entity. Then establish a one-many relationship from Skill
to Post
.
Your FRC should fetch Post
objects (which will by default include all the subentities), using a predicate if necessary to restrict it to those Post
objects related to your desired Skill
object, eg.
NSPredicate(format:"skill.name == %@",self.skillName!)
Upvotes: 1