I'm trying to make an app which will display a popup with of devices with "right" or "left" names depending on whether left or right button was pressed. However, after I press left or right button, the popup appears with empty CollectionView. I colored it green to make sure that it's size is not {0, 0} and it isn't.
Popup screen
Also, I tried to make sure that cells are not bigger than the CollectionView, and it seems, that they are not. I can't put size restraints on them, though, so maybe they get resized or something.
Storyboard
I tried understanding and using solution for that question, but it seems that my situation is somewhat different. In this question cellForItemMethod was called, but in my case it wasn't and I've got no subclass of UICollectionView, which is, I guess, why I cant override intrinsicContentSize.
Here is the code for PopUpViewController:
import UIKit
protocol PopUpDelegate {
func connect(device: CollectionCell)
}
class PopUpController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
static let identifier: String = "PopUpController"
var parentVC: ViewController?
var left: Bool?
let reuseIdentifier = "cell"
var delegate: PopUpDelegate?
var lastSelectedCell: CollectionCell? = nil
#IBOutlet weak var collectionView: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("number of items in section called")
if (left!) {
return (parentVC!.leftDevices.count)
} else {
return (parentVC!.rightDevices.count)
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
print("cell for item called")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! CollectionCell
print("left: ", left!)
if (left!) {
cell.displayDevice(device: parentVC!.leftDevices[indexPath.row])
} else {
cell.displayDevice(device: parentVC!.rightDevices[indexPath.row])
}
cell.backgroundColor = UIColor.white
cell.selectButton.setTitleColor(UIColor.black, for: UIControl.State.normal)
cell.selectButton.setImage(UIImage(named: "unselectedButton"), for: UIControl.State.normal)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
let cell = collectionView.cellForItem(at: indexPath) as! CollectionCell
cell.setSelected()
lastSelectedCell?.setUnselected()
lastSelectedCell = cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print("parent has ", parentVC?.rightDevices.count, " items")
collectionView.reloadData()
}
static func showPopup(parentVC: UIViewController, left: Bool){
//creating a reference for the dialogView controller
if let popupViewController = UIStoryboard(name: "PopUp", bundle: nil).instantiateViewController(withIdentifier: "PopUpController") as? PopUpController {
popupViewController.modalPresentationStyle = .custom
popupViewController.modalTransitionStyle = .crossDissolve
//setting the delegate of the dialog box to the parent viewController
popupViewController.delegate = parentVC as? PopUpDelegate
popupViewController.left = left
parentVC = parentVC as? ViewController
print("showing left popup: ", left)
//presenting the pop up viewController from the parent viewController
parentVC.present(popupViewController, animated: true)
}
}
#IBAction func onConnectPressed(_ sender: Any) {
self.delegate?.connect(device: lastSelectedCell!)
self.dismiss(animated: true, completion: nil)
}
#IBAction func onDismissPressed(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
}
Check again leftDevices and rightDevices data passing between ViewController to PopUpController screen and conform delegate and datasources.
collectionView.delegate = self
collectionView.dataSource = self
Related
I have a tableView, with a prototype cell containing a UICollectionView. I’ve setup the tableView according to this tutorial (https://medium.com/#stasost/ios-how-to-build-a-table-view-with-multiple-cell-types-2df91a206429), and the UI is working. I can pass data through my tableView and into the collectionView.
View Layout
When a collectionViewCell is selected it segues to another view.
I haven’t figured out how to access the data from the collectionViewCell and pass it to the new view.
The collectionView is initialized within the tableView prototype cell. I've tried didSelectRow -> prepareForSegue (code below), but the commands do not autocomplete, and are not working.
Here's the code for the tableViewCell, where the collectionView is setup.
EDIT: Removed commented code for clarity
import UIKit
class homeFeedTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var feedCollectionView: UICollectionView!
var selectedEvent : Event?
var collectionItems = [CollectionViewModelItem]()
var collectionItem : CollectionViewModelItem?
#IBOutlet weak var sectionHeadingLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
feedCollectionView.delegate = self
feedCollectionView.dataSource = self
print("collection items \(collectionItems.count)")
for item in collectionItems{print("type: \(item.type), title: \(item.eventTitle)")}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
// setup view model
var item: TableViewModelItem? {
didSet {
// if not right class, skip
guard let item = item as? TableViewModelFeed else {
return
}
sectionHeadingLabel.text = item.sectionTitle
}
}
// create reuse identifier property
static var identifier: String {
return String(describing: self)
}
}
import Foundation
import UIKit
extension homeFeedTableViewCell {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// print("dataCount3: \(collectionItems.count) \(collectionItems[collectionItems.count-1].type)")
return collectionItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// let cell = UICollectionViewCell()
// return cell
self.collectionItem = collectionItems[indexPath.row]
switch collectionItem!.type {
case .yourEvents:
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier:YourEventsCollectionViewCell.identifier, for: indexPath) as? YourEventsCollectionViewCell{
cell.item = collectionItem
print(cell.item?.type)
print(".yourEvents")
return cell
}
case .feed:
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: mainFeedCollectionViewCell.identifier, for: indexPath) as? mainFeedCollectionViewCell{
cell.item = collectionItem
print(".feed")
return cell
}
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("\(collectionItems[indexPath.row].eventTitle) tapped")
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourEventsToEventViewController" || segue.identifier == "feedToEventViewController"{
print("prepare for segue1")
let destinationVC = segue.destination as! EventViewController
if collectionItem != nil{
print("prepare for segue2")
destinationVC.backgroundImageUrl = collectionItem!.backgroundImageUrl
}
}
}
}
}
A UICollectionView keeps track of its selected indexPaths with the property indexPathsForSelectedItems. Since you trigger your segue in collectionView(didSelectItem: atIndexPath:), your selected indexPath is available during prepare(forSegue:). You could try the following:
class MyViewController: UIViewController, UICollectionViewDelegate {
...
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
performSegue(withIdentifier: "mySegue", sender: self)
}
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard let destinationVC = segue.destination as! EventViewController,
segue.identifier == "mySegue" else { return }
// In this context, your selected cell is the one who fired the segue
if let selectedIndexPaths = collectionView.indexPathsForSelectedItems,
let firstSelectedIndexPath = selectedIndexPaths.first {
let selectedObject = collectionItems[firstSelectedIndexPath.row]
destinationVC?.backgroundUrl = selectedObject.backgroundUrl
}
}
}
The sequence is:
You select a cell (through user interaction, ie tapping).
didSelect performs a segue named "mySegue" (in this example).
In prepareForSegue, you look for your selected index paths. Assuming you aren't using multi-selection, you want your first and only indexPath. Using that index path, you can retrieve your data in your collectionItems array.
I have a collectionView where each cell contains a UIImage and an empty UIButton . How do I the picture that the user tapped on?
class ImageCollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
#IBOutlet weak var imageCollectionView: UICollectionView!
let images: [UIImage] = [
UIImage(named: "beerImage")!,
UIImage(named: "christmasImage")!,
UIImage(named: "goalImage")!,
UIImage(named: "travelImage")!,
UIImage(named: "rollerImage")!,
UIImage(named: "giftImage")!,
UIImage(named: "shirtImage")!,
UIImage(named: "dressImage")!,
]
let columnLayout = FlowLayout(
itemSize: CGSize(width: 150, height: 150),
minimumInteritemSpacing: 30,
minimumLineSpacing: 10,
sectionInset: UIEdgeInsets(top: 20, left: 20, bottom: 10, right: 20)
)
var colViewWidth: CGFloat = 0.0
override func viewDidLoad() {
self.imageCollectionView.collectionViewLayout = columnLayout
super.viewDidLoad()
imageCollectionView.dataSource = self
imageCollectionView.delegate = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCollectionViewCell
cell.imageView.image = images[indexPath.item]
cell.layer.cornerRadius = 2
return cell
}
#IBAction func imageButtonTapped(_ sender: Any) {
print("tapped")
}
#IBAction func closeButtonTapped(_ sender: Any) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let HomeViewController = storyBoard.instantiateViewController(withIdentifier: "HomeVC") as! ExampleViewController
self.present(HomeViewController, animated: false, completion: nil)
}
}
Update
In the end I would like to pass that image to another ViewController. I tried it this way but the picture isn't showing up in the other ViewController:
ViewControllerA
var tappedImage = UIImage()
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
tappedImage = images[indexPath.row]
}
var showPopUpView = true
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print(showPopUpView)
var vc = segue.destination as! ExampleViewController
vc.pickedImage = self.tappedImage
vc.ShowPopUpView = self.showPopUpView
}
ViewControllerB
var pickedImage = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
imagePreview.image = pickedImage
Duo to the conversation in comments:
The order of actions should be:
User clicks on a cell
Fetching the image according to the indexPath of the selected cell
Setting it in a temporary variable (tappedImage)
Performing segue
Pass the temporary image to the destination's temporary image (pickedImage)
Loading the destination's view
Show the image.
Seems like you are missing one of these steps ( probably the step 3, since you are not calling performSegue in the ...didSelectItemAt indexPath... and it maybe not getting called at all! Try print something there and check if it's true )
Or you may disorder the flow ( probably you setting the image after destination's View is loaded and the result is to not seeing that. )
Debug:
Try printing all variables you have access (e.g tappedImage, pickedImage, images[indexPath.row], etc.) on each these 7 states and see where is the issue and where are you loosing the selected image reference
Possible issue
You are not using ...didSelectItemAt indexPath... to performSegue, Probably you have a UIButton for that, so the button is blocking the cell from getting selected.
You could do something like this
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
imageToPass = images[indexPath.row]
}
Edit:
As far as passing that image to your next view controller, one possible way is to add a property to your first and second view controllers for the image, set that image in your didSelectItemAt call, then pass it using prepare(for segue: UIStoryboardSegue, sender: Any?)
let imageToPass: UIImage?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "identifier name here" {
// Get the new view controller using segue.destination.
if let destVC = segue.destination as? SecondViewController {
// Pass the selected object to the new view controller.
destVC.image = imageToPass
}
}
}
Try this
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let image = images[indexPath.row]
//Result image
}
(or)
If you want to get image from button tap (Not recommended)
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCollectionViewCell
cell.imageView.image = images[indexPath.item]
cell.layer.cornerRadius = 2
//Replace your button
cell.yourButton.tag = indexPath.row
cell.yourButton.addTarget(self, action: #selector(self.imageButtonTapped(_:)), for: .touchUpInside)
}
in button action
func imageButtonTapped(_ sender: UIButton) {
let image = images[sender.tag]
//Result image
}
I need to present a new ViewController when selecting a UICollectionView Cell and pass the data from the entity used to fill selected cell.
Here is the code used to fill cell data:
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
}
I understand I need to use didSelectItemAt, I just don't know what information needs to go in the function. Please let me know of anything else needed to better help answer this question. Thank you.
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)
}
I prefer the following architecture:
This is the main controller with data.
For a better understanding, I will simplify the data source.
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...
}
}
In addition to the controller, the child controller also provides a delegate protocol for notification of changes.
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)
}
}
you can follow this to pass information to another view controller.
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
}
I want to present a view controller in FavouriteButtonHandler on a button press.
When I press the button, I get the following error:
Could not cast value of type 'UINavigationController' (0x11177fed8)
I searched for the cause of this error but do not know how to fix it.
View controller code follows:
import UIKit
#available(iOS 11.0, *)
class FirstARViewController: UIViewController , UICollectionViewDelegate , UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionView: UICollectionView!
var imagescv = ["ar1","ar2" ]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imagescv.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! cellimagesar
cell.layer.cornerRadius = 5
cell.layer.borderWidth = 1
cell.myImages.image = UIImage(named: imagescv [indexPath.row])
cell.myImages.contentMode = .scaleToFill
cell.buttonMove.tag = indexPath.item
cell.buttonMove.addTarget(self, action: #selector(self.FavouriteButtonHandler), for: .touchUpInside)
//Declaring cell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 171, height: 250)
}
#objc func FavouriteButtonHandler (sender: UIButton)
{
let VcToPresent = self.storyboard?.instantiateViewController(withIdentifier: "PDFViewController") as! PDFViewController
switch sender.tag {
case 0:
//here you selected Button with tag 0
//Time to update value of Global Struct
ButtonSelected.Tag = 0
//Time to present controller that will handle your pdf file and view it
self.navigationController?.pushViewController(VcToPresent, animated: true)
break
case 1:
//here you selected Button with tag 1
//Time to update value of Global Struct
ButtonSelected.Tag = 1
//Time to present controller that will handle your pdf file and view it
self.navigationController?.pushViewController(VcToPresent, animated: true)
break
default:
print("Error case")
}
}
}
And I get the error in this line :
let VcToPresent = self.storyboard?.instantiateViewController(withIdentifier: "PDFViewController") as! PDFViewController
It's working perfectly for me :
Pushing the PDFViewController into Navigation Stack :
if let presentVC = self.storyboard?.instantiateViewController(withIdentifier: "PDFViewController") as? PDFViewController{
self.navigationController?.pushViewController(presentVC, animated: true)
}
OR
if let presentVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PDFViewController") as? PDFViewController {
self.navigationController?.pushViewController(presentVC, animated: true)
}
Please, make sure that your current viewController should belong to the top of Navigation stack before pushing anything on it.
I have a collection in the ViewController1, if i click that it goes to ViewController2 where i can change a image; when i push back button on the navigation controller to go back in the ViewController1 i should see the image i changed in the ViewController2. My problem is that i need to reload the data of the CollectionView but i can't do it! I already tried to put CollectionView.reloaddata() in the **ViewWillAppear**, but nothing happened! How can i do this?
import UIKit
private let reuseIdentifier = "Cell2"
class CollectionViewControllerStatiVegetarian: UICollectionViewController {
let baza1 = Baza()
#IBOutlet var CollectionViewOut: UICollectionView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
CollectionViewOut.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
let backround = CAGradientLayer().turquoiseColor()
backround.frame = self.view.bounds
self.collectionView?.backgroundView = UIView()
self.collectionView?.backgroundView?.layer.insertSublayer(backround, at: 0)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let size2 = baza1.superTuples(name: "2")
let x = Mirror(reflecting: size2).children.count //
return Int(x+1)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath) as! CollectionViewCell_VegetarianStaty
if indexPath.row != 0 {
cell.shapka_stati_vegetarian.image = nil
let superTupl = baza1.superTuplesShapka(Nomer_tupl: (indexPath.row-1))
cell.label.text = superTupl.5
let tupl = baza1.superTuplesShapka(Nomer_tupl: (indexPath.row-1))
if (tupl.2 == 1) {
cell.shapka_stati_vegetarian.image = nil
cell.shapka_stati_vegetarian.image = UIImage(named: "fon_galochka.png")
} else {}
} else {
cell.shapka_stati_vegetarian.image = UIImage(named: "shapkastaty")
cell.label.text = ""
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let screenWidth = UIScreen.main.fixedCoordinateSpace.bounds.width
let height = screenWidth*550/900+20
var size = CGSize(width: screenWidth, height: 73)
if indexPath.row==0 {
size = CGSize(width: screenWidth, height: height)
}
return size
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row != 0 {
numb_cell = indexPath.row
let bazaSh = Baza()
let f = bazaSh.superTuplesShapka(Nomer_tupl: (indexPath.row-1) )
let vc = storyboard?.instantiateViewController(withIdentifier: "ViewStaty") as! ViewController
vc.obr = f.3
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
Views are loaded only once in the lifetime of a view controller, so viewDidLoad is only run once.
One way to do this is to reload the data in viewWillAppear which is fired when the view appears, but this might run many times.
Another way is to have a delegate method of vc2 that is implemented by vc1. This delegate method is run when the data is changed in vc2 and since vc1 implements the delegate, it can then choose to reload the view.
Yet another way, and one that I prefer, is to use something like Core Data as a model. That way when vc2 changes the data, vc1 can be observing the state of objects it is interested in and react to changes in the model through the NSFetchedResultsControllerDelegate methods.
You could choose to use Realm as a persistence mechanism, and I'm sure there is a similar way to observe the model and react to changes.
inn order to reloadData in background thread, you need to use
DispatchQueue.main.async { self.collectionView.reloadData() }
implement your vc from
UICollectionViewDelegate , UICollectionViewDataSource
then in
viewDidLoad()
self.collectionView.delegate = self
self.collectionView.dataSource = self