I have a complicated situation and I need your help to figure out what should I do.
I have one prototype UIcollectionView, this prototype should be created 4 times for each style type.
I defined these style type as an enum:
enum Colors {
case black, blue, red, green
}
var color = Colors.black
Inside of CollectionViewCell I have also a tableView that has one prototype that contain a label. And there are four arrays that TableViews should be filled by these arrays:
var black = ["black1","black2","black3"]
var blue = ["blue1","blue2","blue3"]
var red = ["red1","red2","red3"]
var green = ["green1","green2","green3"]
now, I tried to make a connection between these TableViews and collectionViews
first for UICollectionView
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.row {
case 0,1,2,3:
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "colors", for: indexPath) as? colorsCell {
switch indexPath.row {
case 1:
self.color = .black
case 2:
self.color = .blue
case 3:
self.color = .red
case 4:
self.color = .green
default:
break
}
return cell
}
default:
break
}
return UICollectionViewCell()
}
Then, for TableView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0,1,2,3:
if let cell = tableView.dequeueReusableCell(withIdentifier: "colCell", for: indexPath) as? colCellDashboard {
switch self.color {
case .black:
cell.title.text = black[indexPath.row]
case .blue:
cell.title.text = blue[indexPath.row]
case .red:
cell.title.text = red[indexPath.row]
case .green:
cell.title.text = green[indexPath.row]
}
return cell
}
return UITableViewCell()
}
The result isn't good enough, the first three tableview in the first three collectionview were filled by blue array, and the last one is correct that filled with green array.
I will be appreciated if you can help me on this.
When the tableView is nested inside the collection you should use
class CollectionCell:UICollectionViewCell,UITableViewDelegate,UITableViewDataSource {
var tableArr = [String]() // table dataSource array
func configure(_ res:[String]) {
tableArr = arr
self.tableView.reloadData()
}
///////
here implement the cellForRowAt and numberOfRows for the nested tableView
}
Inside the vc that contains the collectionView declare the array like this
let arr = [["black1","black2","black3"] , ["blue1","blue2","blue3"] ,
["red1","red2","red3"] , ["green1","green2","green3"]]
Then inside cellForItemAt
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "colors", for: indexPath) as? colorsCell {
cell.configure(arr[indexPath.row])
Ahh, The issue with you code is that in your cellForItemAt delegate method of collection view you are assigning color to a class variable self.color. This will be overwritten for each call to the delegate. So when cellForRowAt delegate for tableview is called it will have the overwritten value of self.color (whatever will be the most updated value) and as a result you will see unexpected entry in your table.
Having tableviews inside collectionViews is kinda common problem. The simplest approach to solve it is:
-Put your datasouce for tableview inside the collectionViewCell.(create a variable in UICollectionViewCell subclass.)
-Assign value to your datasource for each tableView inside cellForItemAt delegate of CollectionView.
-Write all tableViewDelegates inside collectionViewCell and use the datasource varaible of CollectionViewCell to fill tableView.
The key is to underStand that tableView is inside CollectionViewCell and therefore, your CollectionViewCell is responsible to create the tableView.
The CollectionViewCell Structure given be #Sh_Khan looks fine(So not putting similiar code).
Related
I'm making a music app recently, and I'd like to know how to pass data from CollectionView to TableView which has several sections. Here is the home page of my project, and what I want to do is when user tap the image, it will precent another ViewController with the information about the picture. I already know how to present a ViewController by clicking CollectionViewCell inside TableView by delegate, but only if there's only one section.
The thing is that I have 5 sections in this page, and I also have 5 different models for encoding the JSON from API. So how I show the pictures is to send the image urls(from 5 models) to TableViewCell in each section like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: HomeTableViewCell.identifier, for: indexPath) as? HomeTableViewCell else { return UITableViewCell() }
cell.delegate = self
switch homeSections[indexPath.section] {
case .newReleases:
if let newReleases = self.newReleases?.albums.items.map({$0.images[0].url}) {
cell.getPictures = newReleases
}
return cell
case .followSingers:
if let currentlyFollowing = self.currentlyFollowing?.artists.items.map({$0.images[0].url}) {
cell.getPictures = currentlyFollowing
cell.isCircle = true
}
return cell
case .catrgories:
if let categories = self.musicCategory?.playlists.items.map({$0.images[0].url}) {
cell.getPictures = categories
}
return cell
case .artists:
if let playlist = self.relatedArtists?.artists.map({$0.images[0].url}){
cell.getPictures = playlist
}
return cell
case .recentlyPlayed:
if let recentlyPlayed = self.recentlyPlayed?.items?.map({$0.track.album.images[0].url}) {
cell.getPictures = recentlyPlayed
}
return cell
}
}
However, when I want to pass the information which the user tap, there's nothing I can pass but indexPath. I've tried to declare the 5 different model types in TableViewCell, but I still don't know which section did the user tap. Does anyone can help? Thanks a lot!
Update:
To make the question more clearly, please refer to the information below.
In this page, I have a TableView and embed a CollectionView in the TableViewCell, and there's only one ImageView in the CollectionViewCell.
The "New Releases", "Currently Following" and "Categories" are the header of TableView. The "New Releases" is the first section, and the "Currently Following" is the second section, and so on.
Here is how I set cellForItem in CollectionView Delegate. It basically converts String to URL, and display the picture on the screen.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: HomeCollectionViewCell.identifier, for: indexPath) as? HomeCollectionViewCell else { return UICollectionViewCell() }
guard let url = URL(string: getPictures[indexPath.row]) else { return UICollectionViewCell() }
cell.myImageView.getImages(url: url)
if isCircle == true {
cell.myImageView.layer.cornerRadius = cell.myImageView.frame.width/2
}
return cell
}
When the user taps the image, it will only trigger the didSelectItemAt in CollectionView. And I can only pass indexPath.row so far.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate?.sendIndexPath(index: indexPath.row)
}
I read similar questions such as how to have multiple collection view in multiple table view cells and I connected my collection views cells and use identifier names for them but I don't know why I receive this Error:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier extera_infoCollectionViewCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
* First throw call stack:
**Remember that I read Similar questions and the first table view cell with collection view working well and the problem is for second one **
here is my code for main view controller that has a table view and the table view has two cells
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == fieldOfActivityCell().fieldofActivitiesCollectionView {
let fullfields : String = self.adv.resultValue[0].work_field!
let fullfieldsArr : [String] = fullfields.components(separatedBy: ",")
print(fullfieldsArr)
return fullfieldsArr.count
} else {
let extera_infofields : String = self.adv.resultValue[0].extera_info!
let extera_infofieldsArr : [String] = extera_infofields.components(separatedBy: ",")
print(extera_infofieldsArr)
return extera_infofieldsArr.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == fieldOfActivityCell().fieldofActivitiesCollectionView {
let fieldsCells = collectionView.dequeueReusableCell(withReuseIdentifier: "fieldOfActivityCollectionViewCell", for: indexPath) as! fieldOfActivityCollectionViewCell
let fullfields : String = self.adv.resultValue[0].work_field!
let fullfieldsArr : [String] = fullfields.components(separatedBy: ",")
fieldsCells.title.text = fullfieldsArr[indexPath.row]
return fieldsCells
}
else {
let extera_infoCells = collectionView.dequeueReusableCell(withReuseIdentifier: "extera_infoCollectionViewCell", for: indexPath) as! extera_infoCollectionViewCell
let extera_info : String = self.adv.resultValue[0].extera_info!
let extera_infoArr : [String] = extera_info.components(separatedBy: ",")
extera_infoCells.infoText.text = extera_infoArr[indexPath.row]
return extera_infoCells
}
}
and here is the table view codes in same view controller:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0{
let fieldCell = self.showAdvTableView.dequeueReusableCell(withIdentifier: "fieldOfActivityCell", for: indexPath) as! fieldOfActivityCell
return fieldCell
} else {
let fieldCell = self.showAdvTableView.dequeueReusableCell(withIdentifier: "extera_infoCell", for: indexPath) as! extera_infoCell
return fieldCell
}
here is table view first cell class:
class fieldOfActivityCell: UITableViewCell {
#IBOutlet weak var fieldofActivitiesCollectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
if let flowLayout = fieldofActivitiesCollectionView.collectionViewLayout as? UICollectionViewFlowLayout { flowLayout.estimatedItemSize = CGSize.init(width: 1.0, height: 1.0) }
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension fieldOfActivityCell {
func setCollectionViewDataSourceDelegate
<D: UICollectionViewDelegate & UICollectionViewDataSource>
(_ dataSourceDelegate:D , forRow row : Int )
{
fieldofActivitiesCollectionView.delegate = dataSourceDelegate
fieldofActivitiesCollectionView.dataSource = dataSourceDelegate
fieldofActivitiesCollectionView.reloadData()
}
}
and here is the second tableview cell class:
#IBOutlet weak var extra_infoCollectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
if let flowLayout = extra_infoCollectionView.collectionViewLayout as? UICollectionViewFlowLayout { flowLayout.estimatedItemSize = CGSize.init(width: 1.0, height: 1.0) }
}
}
extension extera_infoCell {
func setCollectionViewDataSourceDelegate
<D: UICollectionViewDelegate & UICollectionViewDataSource>
(_ dataSourceDelegate:D , forRow row : Int )
{
extra_infoCollectionView.delegate = dataSourceDelegate
extra_infoCollectionView.dataSource = dataSourceDelegate
extra_infoCollectionView.reloadData()
}
}
First step: using Tags - you just need to use tag for them and use if else to choose which collection view has selected with tag so the answer is this :
if collectionView.tag == 1 {
do some thing//////
}else {
do some thing else}
and you should use this in both cellForRowAtIndexPath and numberOfRows methods you can use this for table view too
Second step: you have to change the name of 'collection view' that you are dequeueing inside the cellForRowAt method in CollectionView data source:
if collectionView.tag == 1 {
let cell = yourFirstCollectionView.dequeueReusableCell(...) as yourCell
....
return cell
} else {
let cell = yourSecondCollectionView.dequeueReusableCell(...) as yourCell
....
return cell
}
According to your error your reuse identifier doesn't match any cell in your storyboard. Click on your extera_info collectionView cell in interface builder. Select the attributes inspector tab. Under reuse identifier make sure you put in extera_infoCollectionViewCell
If you take the other tableview cell In different class , with NSObject features of storyboard it can help you , And it is easy to maintain .
Saeed's tag option above is likely the simplest answer, but found his description a little short so adding a more complete answer below for those who've never used tags before...
If abiding by MVC and placing collectionView dataSource methods inside the UITableView class (instead of inside the UITableViewCell classes), and wanting to avoid this " error:
Each Collection View you use will need its own dequeueReusableCell identifier:
In interface-builder, name all your identifiers for your collection view cells. CatPicCell & DogPicCell for instance.
In your CellForItemAt collectionView method, set up if-statements or switch statement such that each reuse identifier is set equal to the identifiers you created in interface-builder (step 1). If using switch/case, your value can be set to collectionView.tag. Tags can be numbered to identify each different collectionView. The tags are like turning your set of collectionViews into a dictionary or array, such that each collectionView gets its own unique key/index.
Go back into interface-builder, and go into your storyboard and select each collection view (each of which should be inside its own tableView cell). In Xcode's "attribute inspector" scroll down to the "View" section and 3 spaces down (Xcode 11, Swift 5) you'll see a field called "Tag". Assign an integer value to that collection view, and then repeat this process for each collection view which is going to be embedded in your UITableView cells.
Once you have all the collection views tagged with unique integers, you simply set your cases to the integers, and give each dequeueReusableCell identifier the same integer index as you provided in the storyboard.
Now when you tableView cell calls on the collectionView you've outletted in the TableViewCell classes, it will be able to acquire the proper dequeueReusable ID. You can put your data inside each switch case.
Voila, you now have ONE collectionView datasource set of required methods, but serving ALL of your collection views. EVEN BETTER, when someone expands the project and adds another collectionView it will be as easy as adding another case to the switch and identifier in the storyboard.
Example code could look like this:
// I need a switch statement which will set the correct (of the 3 collectionViews) dequeueReusable IDENTIFIER for the collectionView
switch collectionView.tag {
//if tableView is doing cell == 1, then "CatsCell"
//if ... cell == 3, then "DogsCell"
//if ... cell == 5, then "BirdsCell"
case 1:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CatsCell", for: indexPath) as! CatsCVCell
// put your required data here
return cell
case 3:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DogCell", for: indexPath) as! DogsCVCell
// example data
let dogs = dogController.fetch()
cell.name = dogs[indexPath.item].dogName
if let image = UIImage(data: groups[indexPath.item].image!) {
cell.image = image
}
return cell
case 5:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BirdCell", for: indexPath) as! BirdCVCell
// put data code here for birds collection view cells
return cell
default:
return UICollectionViewCell() // or write a fatalError()
}
note: you have two options for your default to the switch statement...
1. like above, a generic but empty cell instance
2. throw an error. The error should never throw bc you'll have all the cases, but an error could occur if someone else improves your code and add another collectionView but forgets to to add the switch case-- so make your error statement explain what's wrong precisely.
I know how to pass data from a UITableViewController to another ViewController. *Both of controllers are UITableViewController.
For example:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
let viewcontroller = NextViewController()
viewcontroller.someText = "Any text"
self.navigationController?.pushViewController(viewcontroller, animated: true)
}
What this does is when I select a cell in the TableViewController, in next view controller, for example a UILabel, say myLabel, is set and a string variable is prepared as someText. And set like self.myLabel.text = someText. And when a row is selected, then in the second view controller, "Any text" will be displayed.
However, this is not what I want to use. By which I mean, my goal I am trying to achieve is:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
//In this case, the next view controller is UITableView.
let viewcontroller = NextViewController()
// I want a selected cell to lead to contain an array of String,
//so that next view controller will hold multiple cells.
// which are only unique to each cell in first TableViewController.
viewcontroller.someArray = array????
self.navigationController?.pushViewController(viewcontroller, animated: true)
}
Update
In my SecondTableViewCOntroller
There is a nvaigationBar and cells are produced by adding text by a UITextField inside UIAlertAction. These data is saved with UserDefaults.standfard with "table2". Also, there is a variable, an array of String set;
//Gloabally Declared
var myArray = [String]();
var array = [String]();
//This function is displayed in didViewLoad()
func data(){
if let myArray = savedata.stringArray(forKey: KEY) {
array = myArray
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
for object in cell.contentView.subviews
{
object.removeFromSuperview();
}
let getData = UserDefaults.standard.stringArray(forKey:"table2")
cell.textLabel?.text = getData[indexPath.row]
cell.textLabel?.font = UIFont(name: familyFont, size: 19)
cell.textLabel?.font = UIFont.systemFont(ofSize: 19)
cell.textLabel?.textColor = UIColor.darkGray
cell.accessoryType = .disclosureIndicator
cell.textLabel?.textAlignment = .center
return cell
}
In my FirstTableViewController:
In this tableViewController, cells are populated by adding text in a UITextField placed on the navigationBar. Then I want the selected cell to hold cells created in SecondTableViewController by adding text by a UITextFieldinsdie UIAlertAction. These data is saved with UserDefaults.standfard with "table1"
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
for object in cell.contentView.subviews
{
object.removeFromSuperview();
}
let getData = UserDefaults.standard.stringArray(forKey:"table1")
cell.textLabel?.myArray = getData[indexPath.row]
cell.textLabel?.font = UIFont(name: familyFont, size: 19)
cell.textLabel?.font = UIFont.systemFont(ofSize: 19)
cell.textLabel?.textColor = UIColor.darkGray
cell.accessoryType = .disclosureIndicator
cell.textLabel?.textAlignment = .center
return cell
}
I do not know how to implement code that achieves this. I have researched posts and googled so hard, but what I could find was only about passing data between a view controller and table view controller, but in my case, it is about passing data between TableView to TableView. So this might help others who have the same trouble too.
This has bugged me for a long time. Please help me...
Thanks!
You are close, and the concept stays the same. In this case you would pass the array of Strings that you want to use in the next tableView and use that array as the datasource for the second table so you would have:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = NewTableViewController()
vc.dataSourceArray = array
self.navigationController.pushViewController(vc, animated: true)
}
Then in your new tableView set your numberForSections(), numForRows(), and cellForIndexPath() based on your dataSourceArray. This will populate the new tableView with the passed data.
As per your question, I think you are trying to send your data to custom view class not to viewController class.
So I suggested to customize the init method of view class.
NB : The code I have shown below is written in Swift 2.1.
Here in the example I have taken a UIView and design table view inside that view. I passed the data from the view controller and showing the list of data as dropdown list.
Code :
In the Custom View
init(frame: CGRect, arrData: NSArray) {
super.init(frame: frame)
arrListData = NSMutableArray(array: arrData)
//In this method I have designed the table view
designListView();
}
In the ViewController :
func ListButtonClicked()
{
let arr = ["Asia", "Europe", "Africa", "North America", "South America", "Australia", "Antarctica"]
dropDownlist = DropdownView(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.size.width, UIScreen.mainScreen().bounds.size.height), arrData: arr);
dropDownlist.backgroundColor = UIColor.clearColor();
self.view.addSubview(dropDownlist)
}
Here I have mentioned part of code, but for your convenience I am adding the output screen so that you can check whether this fulfil your requirement or not.
My output:
We are trying to make a collection view. In each cell the users can choose an image and enter text into a text field. We noticed that after adding four cells, when we add a new cell, the text field is already filled with the information from previous cells. In our code, we never programmatically fill the text field (which starts out empty), we allow the user to do this. Any suggestions?
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Image", forIndexPath: indexPath) as! CollectionViewCell
cell.deleteButton?.addTarget(self, action: #selector(AddNewItem.xButtonPressed(_:)), forControlEvents: UIControlEvents.TouchUpInside)
cell.deleteButton?.layer.setValue(indexPath.row, forKey: "index")
let item = items[indexPath.item]
let path = getDocumentsDirectory().stringByAppendingPathComponent(item.image)
cell.imageView.image = UIImage(contentsOfFile: path)
cell.imageView.layer.borderColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3).CGColor
cell.imageView.layer.borderWidth = 2
cell.layer.cornerRadius = 7
return cell
}
You can use this in UICollectionViewCell custom class
override func prepareForReuse() {
self.profileImg.image = #imageLiteral(resourceName: "Profile Icon Empty")
super.prepareForReuse()
}
Problem is that you are using dequeReusableCellWithIdentifier which returns already created cell(that you were using before). That's why it's already filled with previous data. You need to clear this data before showing this cell, or fill it from some storage(for example array that represents your collection view cells(each object in array somehow related to cell, in your case that is text wroten in cell))
Here's how I ultimately ended up resolving it.
I created an Item class which contained all of the fields which are shown in the collection view cell and created an array of Items.
Here is a simplified version of my CollectionViewCell class, which here only has a single text field:
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var itemName: UITextField!
var item: Item?
func initializeListeners(){
itemName.addTarget(self, action: #selector(itemNameChanged(_:)), forControlEvents: UIControlEvents.EditingChanged)
}
//When the item name is changed, make sure the item's info is updated
func itemNameChanged(textField: UITextField) {
item?.itemName = textField.text!
}
}
Here's a simplified version of the cellForItemAtIndexPath function in my view controller class:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CollectionViewCell
cell.initializeListeners()
let item = items[indexPath.item]
cell.item = item
cell.itemName.text = item.itemName
return cell
}
The reason is that collectionViewLayout.collectionViewContentSize.height
is taller than the real contents size! It is recommended to keep UICollectionView calculate the height automatically (without using UIScrollView, let UICollectionView maintain the scroll), as manual change will cause lots of weird behaviors.
I have a collectionView with 2 sections, each section should be based off the same cell (which only contains a UIImageView).
The only difference between the sections is the number of cells they should contain and types of images displayed.
If I set the cellforItemAtIndexPath method to use a dequeued cell (collectionView.dequeueReusableCellWithIdentifier) everything populates fine, if I set it to use an instance of my custom cell without dequeuing, it crashes.
cellForItemAtIndexPath method:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
//cannot use dequedReusableCell since some cells below scroll-line should remain highlighted
let cell = NumbersCollectionViewCell() // CAUSES CRASH
// let cell = collectionView.dequeueReusableCellWithReuseIdentifier(Constants.cellIdentifier, forIndexPath: indexPath) as! NumbersCollectionViewCell // WORKS FINE
switch indexPath.section {
case 0: cell.imageView.image = UIImage(named: numberImageFiles[indexPath.row])
case 1: cell.imageView.image = UIImage(named: specialNumberImageFiles[indexPath.row])
default: break
}
return cell
}
NumbersCollectionViewCell definition:
class NumbersCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
}
The error that appears is: "Fatal error: unexpectedly found nil while unwrapping an Optional value" and it highlights the "case 0" row in my cellForItemAtIndexPath method.
The reason I don't want to use a dequeued cell is that I need some of the cells to be highlighted at run-time based on user selections, and if I use a dequeued cell it doesn't seem to keep the ones below the scroll-line highlighted.
Assuming that you have both a .swift and a .xib file for your cell, you need to instantiate your NumbersCollectionViewCell like this:
E.g.
let numbersCollectionViewCell = UINib(nibName: "NumbersCollectionViewCell", bundle: bundle).instantiateWithOwner(nil, options: nil)[0] as! NumbersCollectionViewCell
Otherwise, your IBOutlets will not be connected.
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCellWithReuseIdentifier(identifier: "NumbersCollectionViewCell">, forIndexPath: NSIndexPath>) as? NumbersCollectionViewCell else {
print("failed to get cell")
return UICollectionViewCell()
}
switch indexPath.section {
case 0: cell.imageView.image = UIImage(named: numberImageFiles[indexPath.row])
case 1: cell.imageView.image = UIImage(named: specialNumberImageFiles[indexPath.row])
default: break
}
return cell
}