I am currently trying to make a calendar and this error keeps on popping up.
I have tried return 0, and return UICollectionViewCell.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {return 0}
private func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {return }
Non-void function should return a value
If you want to return 0 and UICollectionViewCell,
you should return them
Like this
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "nameOfIdentifier", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {return 0}
First of all, if you're using a UICollectionView, you might need to show atleast 1 UICollectionViewCell in it.
And for that very purpose there is UICollectionViewDataSource methods.
Returning 0 in collectionView(_: numberOfItemsInSection:) won't do anything useful. Its just like I've a collectionView and don't want to show anything in it (until and unless there are specific conditions to return 0).
So, the method must return the number of cells you want to show in the collectionView.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
Now comes the error you're facing: Non-void function should return a value.
The error is because of another UICollectionViewDataSource's methods, i.e. collectionView(_: cellForItemAt:). This method expects you to return the actual collectionViewCell that'll be visible in the collectionView.
In the code you added, you're only calling return. Instead you must return an instance of UICollectionViewCell like so,
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOUR_CELL_IDENTIFIER", for: indexPath)
return cell
}
Related
Have an issue with collection view cell.
i've got a collection view (vertical scroll) with 2 sections (1st is ServiceCell and the 2nd is OfferCell as ). First section is with 1 item - another collection view that is set in class ServiceCell: UIcollectionViewCell {} (horizontal scroll) with multiply subcells (ServiceSubCell).
i can't understand where i have to implement didselect method for subcells
main view conroller looks like this:
extension HomeScreenViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 1
}
return offers.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ServiceCell.reuseId, for: indexPath) as! ServiceCell
return cell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OfferCellSubCell.reuseId, for: indexPath) as! OfferCellSubCell
cell.backgroundColor = .white.withAlphaComponent(0.6)
cell.layer.cornerRadius = 20
cell.setup(with: offers[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.section == 0 {
// this part doesn't work
let serviceVC = ServiceScreenViewController() as ServiceScreenViewController
serviceVC.category = servicesCategoriesArray[indexPath.row]
self.navigationController?.pushViewController(serviceVC, animated: true)
} else {
let offerVC = OfferScreenViewController() as OfferScreenViewController
offerVC.offerNew = offers[indexPath.row]
self.navigationController?.pushViewController(offerVC, animated: true)
}
}
}
Service cell with extension
class ServiceCell: UICollectionViewCell, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return servicesCategoriesArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ServiceCellSubCell.reuseId, for: indexPath) as! ServiceCellSubCell
cell.setup(with: servicesCategoriesArray[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 140, height: 140)
}
}
You should implement "didSelect" in ServiceCell
and you should implement in your ViewController "should highlight" for first section to "false"
func collectionView(_ collectionView: UICollectionView,
shouldHighlightItemAt indexPath: IndexPath) -> Bool {
return yourServiceSection ? false : true
}
the below code must be in ServiceCell and ViewController
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionview.deselectItem(at: indexPath, animated: true)
}
in your "ServiceCell" you must add this extension:
import Foundation
import UIKit
extension ServiceCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewModel.list.count ?? 0
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
ServiceSubCell.nameOfClass,
for: indexPath) as? ServiceSubCell
if let item = viewModel.data?.item(at: indexPath.item) {
cell?.config(item: item)
}
return cell ?? UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: SizeConstant.ServiceSubCellWidth.rawValue,
height: SizeConstant.ServiceSubCellHeight.rawValue)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionview.deselectItem(at: indexPath, animated: true)
// implement your code you need
}
}
I have a collection view cell and inside there's an imageView. On it I display array of images using sd_setImage once loaded from firestore. In console I see all images which my app downloaded.
I use this code:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "newDetailCollectionCell", for: indexPath) as! NewDetailCollectionViewCell
cell.imageView.sd_setImage(with: URL(string: images[indexPath.item]))
return cell
}
When I use this code I can't see my images. But if I use the code below everything works fine.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "newDetailCollectionCell", for: indexPath) as! NewDetailCollectionViewCell
cell.imageView.sd_setImage(with: URL(string: images[indexPath.item]))
return cell
}
The problem is that you should be calling collectionView.reloadData() instead of tableView.reloadData() in your Dispatch.main.async {} Because in this situation the collectionView needs to update the dataSource. I Hope this helps.
DispatchQueue.main.async {
self.collectionView?.reloadData()
}
I have a app which has simple UICollectionView
I am just need when did select any cell from this collectionView app make a vibration
here's my Code
import AudioToolbox
ManualWaveCollectionView : UICollectionViewDataSource , UICollectionViewDelegate , UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "locationsCell", for: indexPath) as! LocationCollectionViewCell
let location = self.cellLocations[indexPath.row]
cell.locationName.text = location.location
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.cellLocations.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
}
}
there are nothing happen it's just keep print () when click in the collectionViewCell
iam using Iphone 5s
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
}
In my app, I am using an UICollectionView. Now I want to develop an UIAlertController, when clicking onto any cell of the collection view.
I started with following code:
extension HomeViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
…
}
// specify cells
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
….
}
// called when widget is moved
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
…
}
// called when clicked
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("Got clicked!")
}
}
But somehow, "Got clicked!" is never printed.
try next:
extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelegate {
}
or
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
...
cell.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap(_:))))
}
func tap(_ sender: UITapGestureRecognizer) {
let location = sender.location(in: self.collectionView)
let indexPath = self.collectionView.indexPathForItem(at: location)
if let index = indexPath {
print("Got clicked on index: \(index)!")
}
}
This is the version using the delegate:
extension HomeViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("item at \(indexPath.section)/\(indexPath.item) tapped")
}
}
Instead of using the extension you can also just add UICollectionViewDelegate and the collectionView(...didSelectItemAt:...) function to the class HomeViewController directly:
class HomeViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("item at \(indexPath.section)/\(indexPath.item) tapped")
}
}
This is because you might have placed some UIButton in the cell. Tap on some empty area in the cell then you will get the 'Got click on index'
I've encountered some unexpected behaviour in my code where UICollectionViewDelegate callbacks are only received if I use the pre-Swift 3 method signatures.
To demonstrate this issue, I have created two view controller subclasses:
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet var collectionView: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
}
// func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
// print(#function)
// }
}
class SubViewController: ViewController {
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
print(#function)
}
func collectionView(_ collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: IndexPath) {
print(#function)
}
}
The callback of interest is the collectionView(_:willDisplay:forItemAt:) method.
The first thing to note is that if I add the old variant of that method (collectionView(_:willDisplayCell:forItemAtIndexPath:)) to ViewController, the compiler helpfully warns me that the method has been renamed:
'collectionView(_:willDisplayCell:forItemAtIndexPath:)' has been renamed to 'collectionView(_:willDisplay:forItemAt:)'
However adding the same method to SubViewController produces no warning – it seems to treat it like it would any other previously-undefined method.
If I run the app with an instance of ViewController (uncomment the collectionView(_:willDisplay:at:) method there, and comment it out in SubViewController), the correct delegate method (with the new method name) is called. If I instead use the class SubViewController, the incorrect delegate method (with the old method name) is called.
Is this the correct behaviour? If so, why? It makes it somewhat difficult to reason about which method signatures I should use, especially when there seems to be no compile-time checking of the method that is actually called in SubViewController.
As pointed out in one of the comments the solution to this problem is to add #objc in front of the function like this.
#objc (collectionView:willDisplayCell:forItemAtIndexPath:)
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
// code goes here
}