How to call collectionView.reloadData() from reusable header button? - ios

I have a button in my reusable header view that deletes information in the array that supplies the data for the collection view and header. I want it to also be able to perform collectionView.reloadData().
The issue is that I can't call collectionView.reloadData() from the header button because it doesn't recognize collectionView as a variable. If I call Builds().collectionView.reloadData() (Builds is the View controller) the app crashes because it says that it found nil while unwrapping optional. I know that simply calling collectionView.reloadData() isn't the problem because i have collectionView.reloadData() called in viewDidAppear() and that gives me no crashes.
Whats going on here? How can I get my collectionView to reload data after the button removes the data?
For reference:
Reusable Header:
import UIKit
class BuildsHeader: UICollectionReusableView {
#IBOutlet weak var headerLabel: UILabel!
#IBOutlet weak var deleteBuildButton: UIButton!
#IBAction func deleteBuildButton(sender: UIButton) {
for hero in heroes{ if hero.hero.name == heroForDetails.hero.name {
hero.builds.removeAtIndex(sender.tag)
heroForDetails = hero
}}
saveToDefaults(userProfile)
//Builds().collectionBuild.reloadData() runs just fine without this line
}
}
ViewController:
import UIKit
class Builds: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionBuild: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collectionBuild.delegate = self
collectionBuild.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(animated: Bool) {
collectionBuild.reloadData()
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCellWithReuseIdentifier("BuildCell", forIndexPath: indexPath) as? TalentsCell {
let build = heroForDetails.builds[indexPath.section]
switch (indexPath.row) {
case 0:
cell.configureCell(build["1"]! as! Talent)
case 1:
cell.configureCell(build["4"]! as! Talent)
case 2:
cell.configureCell(build["7"]! as! Talent)
case 3:
cell.configureCell(build["10"]! as! Talent)
case 4:
cell.configureCell(build["13"]! as! Talent)
case 5:
cell.configureCell(build["16"]! as! Talent)
case 6:
cell.configureCell(build["20"]! as! Talent)
default:
cell.configureCell(build["1"]! as! Talent)
}
return cell
}
return UICollectionViewCell()
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 7
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return heroForDetails.builds.count
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(50,50)
}
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "BuildsHeader", forIndexPath: indexPath) as! BuildsHeader
var buildDict = heroForDetails.builds[indexPath.section]
header.headerLabel.text = buildDict["name"] as! String
header.deleteBuildButton.tag = indexPath.section
return header
}
}

You can achieve that with delegation.
Create a protocol
Create a variable inside BuildsHeader for delegate
Call the delegate method in deleteBuildButton function
Now the code for BuildsHeader should look like this:
import UIKit
//**** The Protocol ****
protocol BuildsHeaderDelegate {
func updateCollectionView()
}
class BuildsHeader: UICollectionReusableView {
//**** Variable for the delegate ****
var delegate: BuildsHeaderDelegate?
#IBOutlet weak var headerLabel: UILabel!
#IBOutlet weak var deleteBuildButton: UIButton!
#IBAction func deleteBuildButton(sender: UIButton) {
for hero in heroes{ if hero.hero.name == heroForDetails.hero.name {
hero.builds.removeAtIndex(sender.tag)
heroForDetails = hero
}}
saveToDefaults(userProfile)
//**** Call the delegate method ****
self.delegate?.updateCollectionView()
}
}
In the viewForSupplementaryElementOfKind method of your collection view configure the delegate property of the header, like this:
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "BuildsHeader", forIndexPath: indexPath) as! BuildsHeader
//**** Set this view controller to be the header's delegate ****
header.delegate = self
// rest of header setup
Make the Builds ViewController confirm to BuildsHeaderDelegate :
class Builds: UIViewController, BuildsHeaderDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
Implement BuildsHeaderDelegate's delegate method in the Builds view controller. you can put this right after your viewForSupplementaryElementOfKind method:
func updateCollectionView () {
//**** reload the collectionView ****
self.collectionBuild.reloadData()
}

Use Delegate to call the method:
protocol BuildsHeaderDelegate(){
func reloadCollectionView()
}
class BuildsHeader: UICollectionReusableView {
var delegate:BuildsHeaderDelegate!
#IBOutlet weak var headerLabel: UILabel!
#IBOutlet weak var deleteBuildButton: UIButton!
#IBAction func deleteBuildButton(sender: UIButton) {
for hero in heroes{ if hero.hero.name == heroForDetails.hero.name {
hero.builds.removeAtIndex(sender.tag)
heroForDetails = hero
}}
saveToDefaults(userProfile)
//##Call delegate method##
delegate.reloadCollectionView()
}
}
Conform delegate in View Controller and Assign it:
class Builds: UIViewController,delegate:BuildsHeaderDelegate , UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionBuild: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collectionBuild.delegate = self
collectionBuild.dataSource = self
}
func reloadCollectionView() {
collectionBuild.reloadData()
}
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "BuildsHeader", forIndexPath: indexPath) as! BuildsHeader
//##Assign Delegate##
header.delegate = self
var buildDict = heroForDetails.builds[indexPath.section]
header.headerLabel.text = buildDict["name"] as! String
header.deleteBuildButton.tag = indexPath.section
return header
}
}

Related

How to debug "unrecognized selector sent to instance" in Swift while the method is not implemented

I have 2 UITextFields in my current view controller. The problem I encounter is when I finish typing in one TextField and try to move the cursor to the other, my app crashed.
I've set up my view controller to implement UITextFieldDelegate. Set the delegate of the two TextFields to be self and implement the textFieldShouldReturn method.
The error message I got is:
[Snapagram.SnapViewController disableEditing:]: unrecognized selector
sent to instance 0x7fabdc55d700.
What I've tried is to use Exception breakpoint, but it only returns to the 1st line of AppDelegate. So I don't know which part of my code to post. Plus, I don't even have disableEditing anywhere in my code. My question are
how can I see which object is calling this method
why is this method being called, despite me not having implemented it
Edit:
this is the entire view controller code, the textFieldShouldReturn is at the bottom.
import UIKit
class SnapViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var chosenThread: Thread!
var entry: ThreadEntry!
var post: Post!
var imageToDisplay: UIImage!
#IBOutlet weak var threadCollectionView: UICollectionView!
#IBOutlet weak var createButton: UIButton!
#IBOutlet weak var imageDisplayed: UIImageView!
#IBOutlet weak var captionField: UITextField!
#IBOutlet weak var locationField: UITextField!
#IBOutlet weak var postButton: UIButton!
override func viewDidLoad() {
imageDisplayed.image = imageToDisplay!
super.viewDidLoad()
postButton.layer.cornerRadius = 25.0
createButton.layer.cornerRadius = 25.0
threadCollectionView.delegate = self
threadCollectionView.dataSource = self
captionField.delegate = self
locationField.delegate = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return feed.threads.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let index = indexPath.item
let thread = feed.threads[index]
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "chooseThreadCell", for: indexPath) as? ChooseThreadCollectionViewCell {
cell.emojiLabel.text = thread.emoji
cell.nameLabel.text = thread.name
return cell
} else {
return UICollectionViewCell()
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
chosenThread = feed.threads[indexPath.item]
entry = ThreadEntry(username: feed.username, image: imageToDisplay)
}
#IBAction func createPressed(_ sender: UIButton) {
chosenThread.addEntry(threadEntry: entry)
}
#IBAction func postPressed(_ sender: Any) {
post = Post(location: locationField.text!, image: imageToDisplay, user: feed.username, caption: captionField.text!, date: Date())
feed.addPost(post: post)
}
}
extension SnapViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return true
}
}

Pass data from CollectionView to TabBarController, than to his childs in Swift

I am new to Swift. Unable to find solution for below problem.
Below is a ViewController with CollectionView and When you click on Cell in CollectionView, data from cell(even this who isn't in label and image view, but are in Book array row) must be send to TabBarCollection, than from TabBarCollection I need to send this data to all of child's, like in this image.
Later in childs of TabBar I will set value of Labels in View Controllers from data from choosed Cell.
Book.swift
import UIKit
struct Book {
let title: String
let image: UIImage?
//Here soon will be more "let", and this data will also have to be send to TabBar but it don't will be show I CollectionViewCell
}
extension Book {
static let books: [Book] = [
Book(title: "Antygona", image: UIImage(named: "imgantygona")!),
//etc
]
}
CollectionViewCell.swift
import UIKit
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var bookImageView: UIImageView!
#IBOutlet weak var bookTitle: UILabel!
func setup(with book: Book) {
bookTitle.text = book.title
bookImageView.image = book.image
}
}
ViewController
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
let books = Book.books
override func viewDidLoad() {
super.viewDidLoad()
let fontAttributes = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16.0)]
UITabBarItem.appearance().setTitleTextAttributes(fontAttributes, for: .normal)
collectionView.dataSource = self
collectionView.delegate = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return books.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "bookCell", for: indexPath) as! CollectionViewCell
let book = books[indexPath.item]
cell.setup(with: book)
return cell
}
}
I saw many solutions but I can't perfectly adapt it to my problem. :(
Thanks for help !
BookInsideViewController.swift
import UIKit
class BookInsideViewController: UIViewController {
#IBOutlet weak var testImageView: UIImageView!
#IBOutlet weak var testLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
You can use collection view DidSelectItemAt function
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "YourtabbarIdentifier") as! UITabBarController
// You should access the `imageController` through your `tabBarController`,
// not instantiate it from storyboard.
if let viewControllers = tabBarController.viewControllers,
let imageController = viewControllers.first as? ImageController {
BookInsideViewController.recivedData1 = Books[indexPath.row]
}
navigationController?.pushViewController(tabBarController, animated: true)
}

How to handle button touch inside the UICollectionviewCell or UITableViewCell

This is a problem that I always stay in dilemma when I creating cells.
Let's say I have a custom cell (PlaceCell) which I'm using in different controllers and collectionviews. It has a label which identify the place name (PlaceNameLabel) and will navigate to place detail when user taps on it.
This doesn't matter controller, collectionviews or wherever cell is used, this is independent of where it is used.
So I have to put the PlaceNameLabel's UITapGestureRecognizer code inside the PlaceCell class.
class PlaceCell: UICollectionViewCell {
#IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
// I have to push a new view controller here
}
}
But if I want to push the place detail view controller I need to access the controller. If I want to access the controller I have two options and this is where I stay in dilemma, I have read lots of SO questions answers most of them suggest the second option, but I think the first one is better approach. But I don't know if it's problem to reference the controller inside the cell.
Could you please share your opinion or any other method to handle this problem?
FIRST OPTION
Referencing the controller inside the cell,
extension MyController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlaceCell", for: indexPath) as! PlaceCell
cell.controller = self
return cell
}
}
class PlaceCell: UICollectionViewCell {
var controller: UIViewController?
#IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
controller.navigationController.pushViewController(PlaceDetailController(),
animated: true)
}
}
SECOND OPTION
Create protocol and delegate, pass event to controller and do whatever you want,
(I think this is not well, because action is about the cell and I have to create protocol function multiple times because I use this Cell in different Controllers)
protocol PlaceCellDelegate {
func handlePlaceNameTouch()
}
class PlaceCell: UICollectionViewCell {
var delegate: PlaceCellDelegate?
#IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
delegate?.handlePlaceNameTouch()
}
}
extension MyController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, PlaceCellDelegate {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlaceCell", for: indexPath) as! PlaceCell
cell.delegate = self
return cell
}
func handlePlaceNameTouch() {
self.navigationController.pushViewController(PlaceDetailController(), animated: true)
}
}
You no need to handle specially to cell selection. No need to use UITapGestureRecognizer or no need implement your own protocol to detect cell selection.
UICollectionView and UITableView has its own protocols for that.
Cell selection delegate for UICollectionView - UICollectionViewDelegate protocol
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
Cell selection delegate for UITableView - UITableViewDelegate protocol
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Confirm protocol & set delegate on your UIViewController
class viewcontroller : UICollectionViewDelegate {
#IBOutlet weak collectionView: UICollectionView!
func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
}
}
And implement the protocol method inside a view controller, which I mentioned above.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//indexPath - Index path of selected cell.
// Add you cell selection logic here.
}
This method will be triggered when you tap on the cell. Inside this method fetch the model from datasource array. and navigate to detail view based on which cell (model) selected by user.
While both your options are possible, if you are hesitating I would recommend the delegate approach as it is a more "swifty" way of doing it and makes the cell reusable.
Here is a third option using an onTapHandler which doesn't use the delegate pattern and still keeps the cell reusable:
class PlaceCell: UICollectionViewCell {
// A handler called when the button is pressed
var onTapHandler: (() -> Void)?
#IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
// Make sure the handler exists, else...
guard let handler = self.onTapHandler else {
return
}
// Execute handler
handler()
}
}
You would then use it like so:
extension MyController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, PlaceCellDelegate {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlaceCell", for: indexPath) as! PlaceCell
cell.onTapHandler = { [weak self] in
self?.navigationController.pushViewController(PlaceDetailController(), animated: true)
}
return cell
}
}

Use CollectionView methods from another swift file

I'd like to use a CollectionView methods from another swift file instead of it's ViewController for some reason.
I have this in my ViewController:
#IBOutlet weak var collectionView: UICollectionView!
var broadcastColletionView = BroadcastCollectionView()
override func viewDidLoad() {
super.viewDidLoad()
broadcastColletionView = BroadcastCollectionView(eventItems: eventItems,collectionView: collectionView, broadastObject: broadastObject)
collectionView.dataSource = broadcastColletionView
collectionView.delegate = broadcastColletionView
}
And I have BroadcastCollectionView.swift which contains the CollectionView delegate methods:
class BroadcastCollectionView: NSObject,UICollectionViewDelegate, UICollectionViewDataSource {
var eventItems = [Eventtype]()
var alreadyChecked: Bool = false
var cellHistory: IndexPath = []
var collectionView: UICollectionView!
var broadastObject = Broadcast()
init(eventItems: [Eventtype],collectionView: UICollectionView,
broadastObject: Broadcast) {
self.eventItems = eventItems
self.collectionView = collectionView
self.broadastObject = broadastObject
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return eventItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "brCollectionView", for: indexPath) as! BroadcastCollectionViewCell
self.collectionView = collectionView
cell.eventImage.image = eventItems[indexPath.row].image
cell.eventType = eventItems[indexPath.row]
let tap = UITapGestureRecognizer(target: self, action: #selector(collectionViewTapped))
tap.numberOfTapsRequired = 1
cell.addGestureRecognizer(tap)
return cell
}
#objc func collectionViewTapped(sender: UITapGestureRecognizer) {
if let indexPath = self.collectionView?.indexPathForItem(at: sender.location(in: self.collectionView)) {
let cell : BroadcastCollectionViewCell = collectionView.cellForItem(at: indexPath)! as! BroadcastCollectionViewCell
print("item index")
} else {
print("collection view was tapped")
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("selected row is",indexPath.row)
}
I don't really understand why the delegate methods not called if I setted the collectionView.delegate and dataSource to the BroadcastCollactionViewclass. Please don't make me explain why would I like to separate this CollectionView it's not part of the question.
After setting datasource and delegate for the collection view in viewDidLoad() method, reload the collection view:
collectionView.reloadData()
This another class that you created is called CustomDataSource you can find a tutorial here
Try calling
collectionView.reloadData() after setting the dataSource and delegate.
and Make sure eventItems is not empty.
Hope it Helps!
Apart from the issue of not working in your case which could be due to not configuring the collection view properly which can be resolved using the answers you got above from other users, There is an approach for your question of "Use CollectionView methods from another swift file"
You can make use of the concept called "extension", I will explain you how.
Create a new class for handling the collection view methods as follows,
class MyDataSource: NSObject {
var eventItems: Array<Any>?
init(events: Array<Any>?) {
self.eventItems = events
}
}
extension MyDataSource: UITableViewDataSource, UITableViewDelegate {
// MARK: - Table view data source methods
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier")
return cell
}
// Add additional data source methods & delegate methods as per your need
// MARK: - Table view delegate methods
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Perform your action
// Use delegate methods(protocols) to do your actions from the viewController class
}
}
And in the viewController file assign the datasource & delegate method for collection view as follows,
class ViewController: UIViewController {
var datasource: MyDataSource?
override func viewDidLoad() {
super.viewDidLoad()
// Initialize datasource & delegate for collectionView with the extension datasource
datasource = MyDataSource(events: EVENTITEMS_ARRAY)
collectionView?.dataSource = datasource
collectionView?.delegate = datasource
}
}
NOTE
Update the data types & collection view properties like cell identifier as per your need.

cellForItemAtIndexPath indexPath not called for multiple collection views in a single UIViewController

I am trying to have multiple collection views in a single view controller. I have tried to achieve that by using separate tags for each collection views, but it seems to me that the celForItemAtIndexPath is not being invoked. The following is my code for UIViewController.
import UIKit
class HomeViewController: UIViewController {
// MARK: - IBOutlets
#IBOutlet weak var backgroundImageView: UIImageView!
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var friendsCollectionView: UICollectionView!
// MARK: - UICollectionViewDataSource
private var interests = Interest.createInterests()
private var friends = Friends.createFriends()
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.tag = 100;
self.friendsCollectionView.tag = 200;
collectionView.registerClass(NSClassFromString("InterestCell"),forCellWithReuseIdentifier:"cell");
friendsCollectionView.registerClass(NSClassFromString("FriendCell"),forCellWithReuseIdentifier:"cellB");
self.view.addSubview(collectionView)
self.view.addSubview(friendsCollectionView)
print("view did load")
}
private struct Storyboard {
static let CellIdentifier = "InterestCell"
static let FriendIdentifier = "FriendCell"
}
}
extension HomeViewController : UICollectionViewDataSource {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
print("number of sections are 1")
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
print("trying this")
if collectionView.tag == 100 {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(Storyboard.CellIdentifier, forIndexPath: indexPath) as! InterestCollectionViewCell
print("inside pluto")
return cell
}
else {
let cellB = friendsCollectionView.dequeueReusableCellWithReuseIdentifier(Storyboard.FriendIdentifier, forIndexPath: indexPath) as! FriendListCollectionViewCell
print("inside venus")
return cellB
}
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("hello")
if collectionView == collectionView {
print(interests.count)
return interests.count
}
else {
print("hmmm")
return friends.count
}
}
}
Can someone please suggest what I'm doing wrong?
To reach the cellForItemAtIndexPath method, you have to set the collectionView datasource like :
collectionView.dataSource = self;
friendsCollectionView.dataSource = self;
Also, it would be better instead of using tags to recognize each collection, using something similar to :
if (collectionView == self.collectionView) { } else if (collectionView
== self.friendsCollectionView) { // init friend cell ... }
You should specify the delegate and the dataSource of your collection.
collectionView.delegate = self
collectionView.dataSource = self
Remember to add UICollectionViewDelegate and UICollectionViewDataSource to your ViewController.
Did you correctly setup datasource and delegates? Since the class is not compliant to UICollectionViewDataSource and UICollectionViewDelegate, I guess no. Do this in viewDidLoad:
collectionView.delegate = self
collectionView.dataSource = self
friendsCollectionView.delegate = self
friendsCollectionView.dataSource = self
or do it via xib.
Make the class compliant to UICollectionViewDataSource and UICollectionViewDelegate by editing the class declaration:
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource
I suggest you to use references to objects instead of tags. Refer to the collectionviews by checking if the collectionView object of the delegates is equal to the one you've instantiated:
if collectionView == self.friendsCollectionView { //do something }
if collectionView == self.collectionView { //do something }

Resources