【问题标题】:How to setup a collectionView (or TableView) with NSFetchedResultsController and multiple fetched entities如何使用 NSFetchedResultsController 和多个获取的实体设置 collectionView(或 TableView)
【发布时间】:2020-05-03 15:46:39
【问题描述】:

我在这里读到,使用 1 个 NSFetchedResultsController 获取多个实体的方法是使用父子继承模型。我有这样一个模型:

https://imgur.com/a/nckHzvr

如您所见,TextPost、VideoPost 和 ImagePost 都有 Skill 作为父实体。我正在尝试制作一个所有三个孩子都出现的collectionView。我对如何设置委托方法有点困惑......

这是视图控制器的代码

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
    }
}

由于实际上只返回了 1 个实体,我不确定如何访问特定索引路径中的元素。例如 SkillFetchedResultsController[indexPath.row] 我认为只有 1 个实体 - 技能本身。我真的很想访问它的孩子。我是否必须以某种方式继承 SkillFetchedResultsController 并只返回我感兴趣的孩子?

编辑:@pbasdf 建议 - 我有这个模型:

现在当我像这样创建一个实体时:

        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()

然后我设置我的获取结果控制器来查看“Post2”,如下所示:

    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")
        }

    }

我没有看到返回结果:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    guard let sectionInfo = skillFetchedResultsController.sections?[section] else { return 0 }
    return sectionInfo.numberOfObjects
}

我是否需要以某种方式将两者联系起来?就像同时创建 Post 对象和 TextPost 对象一样?当我尝试直接获取 TextPost 对象时,它可以工作。

【问题讨论】:

  • 让我检查一下我是否理解您的模型:一个技能可以有多个帖子(并且帖子仅与一个技能相关),但每个帖子可以是 TextPost、ImagePost 或 VideoPost?
  • @pbasdf 正确。

标签: ios uitableview core-data uicollectionview nsfetchedresultscontroller


【解决方案1】:

我认为问题在于您的模型。您应该创建一个Post 实体,并使其成为TextPostVideoPostImagePost 的父实体。如果您的子实体有任何共同的属性,请将它们从子实体移动到Post 实体。然后建立从SkillPost的一对多关系。

您的 FRC 应获取 Post 对象(默认情况下将包括所有子实体),如有必要,使用谓词将其限制为与您所需的 Skill 对象相关的 Post 对象,例如。

NSPredicate(format:"skill.name == %@",self.skillName!)

【讨论】:

  • 是 NSPredicate(format:"skill.name == %@",self.skillName!) 要走的路吗?而不是 NSPredicate(format:"skill == %@",self.skill!) ?
  • 如果您有Skill 对象本身,请使用它(即"skill == %@",self.skill)。我根据你的代码使用了skillName,但是使用对象效率更高。
  • 我将模型更新为我认为您所指的内容。检查帖子中的编辑。
  • 您已经按照我的描述实现了它,但我无法立即看到为什么 Post2 FRC 未获取您的 TextPosts 并因此未出现在 collectionView 中。我会考虑一下的。
  • 我认为它基本上可以按照您的描述工作。我必须在我的代码中做错了什么。我创建了这个简单的应用程序,以表明它可以按照您的描述工作:github.com/AlexMarshall12/test-nfc-fetch-children,以防您或其他人想尝试它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-19
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 2012-06-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多