【问题标题】:Pass coredata to ViewController based on cell selection根据单元格选择将 coredata 传递给 ViewController
【发布时间】:2019-07-05 08:52:29
【问题描述】:

我需要在选择 UICollectionView 单元格时显示一个新的 ViewController,并从用于填充所选单元格的实体传递数据。

这是用于填充单元格数据的代码:

   let pets = PersistenceManager.shared.fetch(Pet.self)
     var _fetchResultsController: NSFetchedResultsController <Pet>?
    var fetchResultsController: NSFetchedResultsController <Pet>?{
        get{
            if _fetchResultsController == nil {

                let moc = PersistenceManager.shared.context
                moc.performAndWait {
                    let fetchRequest = PersistenceManager.shared.petsFetchRequest()
                    _fetchResultsController = NSFetchedResultsController.init(fetchRequest: fetchRequest, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil) as? NSFetchedResultsController<Pet>
                    _fetchResultsController?.delegate = self
                    do {
                        try self._fetchResultsController?.performFetch()
                    }catch {
                    }
                }
            }
            return _fetchResultsController
        }
    }

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionViewHorizontal.dequeueReusableCell(withReuseIdentifier: "HorCell", for: indexPath) as! PRMainHorizontalCollectionViewCell

        if let pet= self.fetchResultsController?.fetchedObjects, indexPath.row < pet.count{
            let _pet= fetchResultsController!.object(at: indexPath)
// cell UI goes here
        }
        return cell
    }

我知道我需要使用 didSelectItemAt,我只是不知道函数中需要输入哪些信息。请让我知道需要更好地帮助回答这个问题的其他任何事情。谢谢。

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

// Added the line below based on karthik's answer. But I am unsure how to implement it.
    let selectedObj = fetchResultsController!.object(at: indexPath)

    let vc = self.storyboard?.instantiateViewController(withIdentifier: "selectedPetViewController") as! PRSelectedPetViewController

    navigationController?.pushViewController(vc, animated: true)

}

【问题讨论】:

  • 在选择时获取带有indexpath fetchResultsController!.object(at: indexPath)的选定对象,然后将其传递给另一个视图控制器。
  • 初始化fetchResultsController的方式很丑陋,而且objective-c-ish。在 Swift 中,NSFetchedResultsController 应该被初始化为非可选和原生的lazy var fetchResultsController: NSFetchedResultsController&lt;Pet&gt; = { .... }()
  • ☝️☝️☝️ 没错,但这并没有解决 OP 的问题。
  • 你使用segue吗?
  • @vadian 我看到苹果还使用lazy var 而不是let 来初始化fetchResultsController。为什么在使用NSFetchResultsController 时使用lazy var 而不是let

标签: ios swift core-data uicollectionview


【解决方案1】:

我更喜欢以下架构:

这是带有数据的主控制器。 为了更好地理解,我将简化数据源。

class ViewController: UIViewController {
    // code ...

    @IBOutlet var collectionView: UICollectionView!
    fileprivate var data = [Pet]()
}

extension ViewController: UICollectionViewDataSource {
    // code ...

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return data.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HorCell", for: indexPath) as? PRMainHorizontalCollectionViewCell else {
            return UICollectionViewCell()
        }

        let pet = data[indexPath.row]
        // TODO: configure cell using pet ...
        return cell
    }

}

extension ViewController: UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let row = indexPath.row
        let pet = data[row]

        // TODO: Get the child controller in any way convenient for you.
        let childController = ChildViewController()
        // With the help of the delegate, we will receive notification of changes pet.
        childController.delegate = self

        // Thus, we pass the data to the child controller.
        childController.pet = pet
        childController.indexPath = indexPath

        // TODO: Present the view controller in any way convinient for you.
    }

}

extension ViewController: ChildViewControllerDelegate {

    func saveButtonPressed(_ controller: ChildViewController) {
        guard let pet = controller.pet, let indexPath = controller.indexPath else {
            return
        }

        // We save data and reload the cell whose data we changed.
        self.data[indexPath.row] = pet
        collectionView.reloadItems(at: [indexPath])
    }

    func cancelButtonPressed(_ controller: ChildViewController) {
        // Do something if necessary...
    }

}

除了控制器之外,子控制器还提供了一个委托协议,用于通知更改。

protocol ChildViewControllerDelegate {

    func saveButtonPressed(_ controller: ChildViewController)

    func cancelButtonPressed(_ controller: ChildViewController)

}

// This is the controller you want to show after selecting a cell.
// I assume that in the child controller there is a button to save and cancel.
class ChildViewController: UIViewController {

    var delegate: ChildViewControllerDelegate?

    // The object whose data we are editing in the controller.
    var pet: Pet!

    // The location of the object in the main controller.
    var indexPath: IndexPath!

    override func viewDidLoad() {
        // TODO: Configure user interface using self.pet
    }

    @IBAction func saveButtonPressed(_ button: UIButton) {
        delegate?.saveButtonPressed(self)
    }

    @IBAction func cancelButtonPressed(_ button: UIButton) {
        delegate?.cancelButtonPressed(self)
    }

}

【讨论】:

  • 感谢您的回答。它编译但在 ChildViewController 中,'var pet: Pet!'和 'var indexPath: IndexPath!'每次都为零。
  • @icestorm0806,它们是在ViewController类的方法didSelectItemAt中设置的
  • 我在问为什么它们在 ChildViewController 中为零。 didSelectItemAt 与您的相同。
  • @icestorm0806,也许你忘了给collectionView设置一个委托,所以方法didSelectItemAt甚至没有被调用,因此这些变量没有被初始化?如果是这样,请将行 collectionView.delegate=self 添加到 viewDidLoad。唯一的例外是如果您使用segue。在这种情况下,应该在方法func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)中进行这样的初始化
  • 委托已经设置,我没有在这个项目中使用故事板。为了避免任何问题,我基本上遵循了您回答中的所有内容。
【解决方案2】:

您可以按照此将信息传递给另一个视图控制器。

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        let selectedObj = fetchResultsController!.object(at: indexPath)
        // instantiate presenting view controller object
        // add one property (manange object) in your presenting viewcontroller
        // assign the selected object to that property
        // present the view controller
    }

【讨论】:

  • 您能解释一下“在呈现的视图控制器中添加一个属性(管理对象)”和“将所选对象分配给该属性”是什么意思吗?我能够实例化并呈现良好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-14
  • 2017-09-27
  • 1970-01-01
  • 2018-03-21
相关资源
最近更新 更多