I have made a UICollection View. In my ViewController I have the following code:
import UIKit
import AlamofireImage
class MYViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, MYItemCellDelegate {
let viewModel : MYViewModel = StandPlaceViewModel()
#IBOutlet weak var itemCollectionView: UICollectionView!
#IBOutlet weak var ItemCountLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.viewModel.getItems(self.viewModel.stand) { items in
self.ItemCountLabel.text = String(self.viewModel.itemCount)
self.itemCollectionView.reloadData()
}
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.viewModel.tableDict.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
print("IN COLLECTION OF ITEMS")
let cell: MYItemCell = collectionView.dequeueReusableCellWithReuseIdentifier("itemCell", forIndexPath: indexPath) as! MYItemCell
cell.itemTitleLabel.text = self.viewModel.tableDict[indexPath.row]![0]
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("Cell \(indexPath.row) selected")
}
...
My Issue is that the UICollection never loads. IN COLLECTION OF ITEMS is never printed. I have a separate page with a collection and it all works just fine and I cant find the difference.
The ItemCountLabel.text is properly set in the viewDidLoad(), but the reloadData() never seems to call the collectionView code.
I would expect IN COLLECTION OF ITEMS to be printed twice.
Add these code into viewDidLoad
self.itemCollectionView.delegate = self;
self.itemCollectionView.dataSource = self;
Related
I get this error when I try to append an image to my image array in IOS swift: Thread 1:signal SIGABRT
It occurs when I call the loadImages() function:
import UIKit
class ProtectedGallery: UIViewController, UICollectionViewDataSource {
#IBOutlet weak var imageCollection: UICollectionView!
var images = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
loadImages()
}
func loadImages()
{
images.append(UIImage(named: "image1")!)
self.imageCollection.reloadData()
}
func collectionView(_ imageCollection: UICollectionView, numberOfItemsInSection section: Int)-> Int{
return images.count
}
func collectionView(_ imageCollection: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = imageCollection.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! ImageCollectionViewCell
let image = images[indexPath.row]
cell.imageView.image = image;
return cell
}
}
Any ideas why this is the case? I have been stuck on this for a while.
I've just noticed a few things:
First, you never set the data source (or delegate) for your collection view. Do that:
class ProtectedGallery: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var imageCollection: UICollectionView! {
didSet {
imageCollection.dataSource = self
imageCollection.delegate = self
}
}
}
Also, your data source method arguments are not named correctly. Change to this:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// put your code here
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// put your code here
}
This question already has answers here:
Outlets cannot be connected to repeating content iOS
(9 answers)
Closed 4 years ago.
I followed the attached guide to creating static UICollectionView but now I would like to add buttons to each cell and change the text on the buttons, for example. I can not do this and get the error "UIButton is invalid. Outlets cannot be connected to repeating content." How can I fix this issue and use IBOutlets with objects in cells without leaving the ViewController?
If I need to leave ViewController please describe the process with a lot of detail as I am a beginner and am not too knowledgeable on the different view classes.
Thank you!!
Instead of the outlet between the button and the view controller, you should create a subclass of UICollectionViewCell, and add your IBOutlets on that class.
class MyCollectionViewCell: UICollectionViewCell {
#IBOutlet var myButton: UIButton!
}
Then, in Interface Builder, set this subclass to be the class of your cells (in the Identity inspector pane).
You should then be able to create the outlet connection from your button to your cell.
I hope this is clear enough. If not, please let me know!
Example code
class MyCollectionViewCell: UICollectionViewCell {
#IBOutlet var myButton: UIButton!
}
class MyViewController: UIViewController, UICollectionViewDataSource {
#IBOutlet var myCollectionView: UICollectionView!
private var isMyButtonEnabled = true
// Other view controller code
func disableMyButton() {
self.isMyButtonEnabled = false
self.myCollectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = ... as! MyCollectionViewCell // Get cell
// Other cell setup
cell.myButton.isEnabled = self.isMyButtonEnabled
return cell
}
}
Define class like following for your collection view:
class MyCollectionCell : UICollectionViewCell {
#IBOutlet weak var likeButton: UIButton?
}
Create xib for collection cell and use above custom class for collection view.
Now in your view controller define collection view and implement following delegates UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout.
class ViewController: UIViewController, UICollectionViewDataSource,
UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
#IBOutlet var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "MyCollectionViewCell", bundle: nil)
collectionView?.registerNib(nib, forCellWithReuseIdentifier: "myCell")
}
//UICollectionViewDelegateFlowLayout methods
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat
{
return 4;
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat
{
return 1;
}
//UICollectionViewDatasource methods
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell =
collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as MyCollectionCell
cell.likeButton.setTitle("myTitle", for: .normal)
cell.likeButton.tag = indexPath.row
cell.likeButton.addTarget(self, action: #selector(mainButton:), forControlEvents: .TouchUpInside)
return cell
}
#IBAction func mainButton(sender: UIButton) {
println(sender)
// use button tag to find out which button is clicked.
}
}
In above code important method is func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell where you set tag to your button and then use that tag to find out which button is pressed and use that id to find out data source or action you want to perform.
I am attempting to segue from a UICollectionViewCell to a new ViewController. I have created a segue from one ViewController to the other and created the code below for when I select the cell.
class FilmsViewController: UIViewController, UICollectionViewDelegate,
UICollectionViewDataSource, UICollectionViewDelegateFlowLayout,
UISearchBarDelegate {
var films: [NSDictionary]?
var filteredFilms: [NSDictionary]?
let searchBar = UISearchBar()
//let searchController = UISearchController(searchResultsController: nil)
#IBOutlet var filmsTable: UICollectionView!
#IBOutlet var navLogo: UINavigationItem!
#IBOutlet var search: UIBarButtonItem!
#IBOutlet var back: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
self.filmsTable.dataSource = self
self.filmsTable.delegate = self
loadFilms()
}
func collectionView(_ _collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return filteredFilms?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = filmsTable.dequeueReusableCell(withReuseIdentifier: "filmCell", for: indexPath) as! FilmCell
let film = filteredFilms![indexPath.row]
let title = film["title"] as! String
cell.titleLabel.text = title
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: NSIndexPath) {
let film = filteredFilms![indexPath.row]
performSegue(withIdentifier: "detailsSegue", sender: film)
}
The problem is nothing happens when I select the cell. There is no error just no response to clicking in any of the cells. I believe the issue is the cell is not responding to being clicked but I am not sure why.
EDIT: I have also tried:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: NSIndexPath) {
performSegue(withIdentifier: "detailsSegue", sender: FilmCell)
}
With FilmCell being the UICollectionViewCell
FilmCell Class:
class FilmCell: UICollectionViewCell {
#IBOutlet var posterImage: UIImageView!
#IBOutlet var titleLabel: UILabel!
override func awakeFromNib() {
}
}
Try this :
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegue(withIdentifier: "detailsSegue", sender: nil)
}
I had a UITapGesture used for resigning the keyboard connected to the collection view. I was more than 100% certain I had already tried deleting the gesture and the code for it. Apparently I had not deleted it fully because I went back and tried again and this solved the issue. Tap Gestures inside of collection views sit over the cells causing them not to be selected on touch.
The solution was, DO NOT have a UITapGesture in your UICollectionView.
I am working on a meme generator app. The meme generator is presented modally and is built into a tab bar view controller. The first tab displays all saved memes in a table view and the second is intended to display the saved memes in a collection view. The meme generator works as design and is saving generated memes to an array that is located in the App Delegate file (I know this is controversial, but it is a requirement of the exercise). I am attempting to set up the collection view and I am not able to get a reference to the meme object in the app delegate file and I don't understand why.
import UIKit
class CollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
var memes: [Meme]! {
didSet {
collectionView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
memes = appDelegate.memes
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return memes.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.imageView.image = memes[indexPath].memedImage
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
}
I based this code on the code used for my table view, which works as designed. That code is:
import UIKit
class TableViewMemesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var memes: [Meme]! {
didSet {
tableView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
memes = appDelegate.memes
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return memes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
let meme = memes[indexPath.row]
cell?.imageView?.image = meme.memedImage
cell?.textLabel?.text = meme.topText
return cell!
}
}
How can I get a reference to the array data and display it inside of the collection view when the user saves a new meme? Here is a link to the repo.
You have some issues, first you have to create a Custom CollectionViewCell:
class Cell: UICollectionViewCell {
#IBOutlet var imageView:UIImageView!
}
remember to set the Custom Class for UICollectionViewCell inside the storyboard:
then when you dequeue the cell, be sure of as! Cell:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
cell.imageView.image = memes[indexPath.row].memedImage
return cell
}
Then inside your TabBarStoryboard.storyboard, you must set delegate and datasource for your CollectionViewController (I checked your github, you didn't attach them).
Finally the result will be:
I want to create a screen layout . A main UICollectionView class scrolling horizontally on the top 1/3 of the screen, followed by a table on the bottom 2/3, but in the table I would like to slide multiple images horizontally, so I thought of putting another collection view in the table cell. I've connected the datasource and delegate for the main collection view to the main view controller and that works. the table view is connected up to the main view controller as well.
Screenshot of IB shows what I want to do, only able to do what is shown on left. Can only implement main collectionview and underneath table.
want to create main collectionview and table with collection view in cells with headers on top of each row.
When I connect the second collectionview( the one in the table) either to the main viewcontroller or to the custom tablecell, i get various different runtime errors.
When connected to the tableview I get this error:
UITableView collectionView:numberOfItemsInSection:]: unrecognized
selector sent to instance 0x7fb009064800
My code is attached. Unfortunately, I cannot get the UICollectionview to appear in the Table.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MainCell", forIndexPath: indexPath) as! CollectionViewCell
return cell
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TableCell", forIndexPath: indexPath) as! TableViewCell
return cell
}
}
TableViewCell class
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var subCollectionViewObject: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension TableViewCell: UICollectionViewDataSource, UICollectionViewDelegate {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 15
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let subCell = collectionView.dequeueReusableCellWithReuseIdentifier("SubCell", forIndexPath: indexPath) as! SubCollectionViewCell
return subCell
}
}
import UIKit
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var mainImage: UIImageView!
}
import UIKit
class SubCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var subImage: UIImageView!
}
Solved the issue using a scrollview inside a tableview. Easier for me to conceptualize and implement.