UIButton in CollectionViewCell "IndexPath doesn't work" - swift

I made a simple app add uibutton to collectionviewcell but when i give action an error occurs. Here is a screenshoot.
Error 1
Error 2
and my code of class: UIbuton {}
import Foundation
import UIKit
class KeypadUIButton: UIButton {
var qIndex : NSIndexPath?
}
and my cell class is :
import UIKit
class ConverterCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var keypadButton: KeypadUIButton!
}
and error in :
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = padCollectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! ConverterCollectionViewCell
let index = indexPath.row
// -> cell.keypadButton.qIndex = indexPath as NSIndexPath
return cell
}
Where is my mistake. can you help me ?

Oh! I've got your error, it seems you missed this:
Type in your class name: KeypadUIButton
Also you don't need to use NSIndexPath in swift. Just use IndexPath instead. So you won't need to down cast it.

I have try with your code its work fine , please check that you give action to your button as well as custom class name to your button
class KeypadUIButton: UIButton {
var qIndex : NSIndexPath?
}
class ConverterCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var keypadButton: KeypadUIButton!
}
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{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 16
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let identifier : String = "test"
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! ConverterCollectionViewCell
cell.keypadButton.qIndex = indexPath as NSIndexPath?
cell.keypadButton.setTitle("\(indexPath.row + 1)", for: .normal)
return cell
}
}

You had taken
qIndex as? NSIndexPath
you can take as
qIndex as? Indexpath
It avoid unnecessary downcasting in cellforitem.

Related

How to get all collectionview cell index inside tableview cell using Protocol in Swift

I am using collectionview inside tableview cell. so when collectionview cell button is clicked then present viewcontroller i am using protocol..
code for tableviewcell and delegate:
protocol CustomCellDelegate: class {
func sharePressed(cell: ProposalTableVIewCell)
}
class ProposalTableVIewCell: UITableViewCell, UICollectionViewDelegate,UICollectionViewDataSource {
#IBOutlet weak var attetchmentsCollectionview: UICollectionView!
var delegate: CustomCellDelegate?
public var bidAttatchment: Array<Get_attachments>?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return bidAttatchment?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AttatchmentCollectionViewCell", for: indexPath) as! AttatchmentCollectionViewCell
let attatchBid = bidAttatchment?[indexPath.item]
cell.attatchmentLbl.text = attatchBid?.filename
cell.openBtn.tag = indexPath.item
cell.openBtn.addTarget(self, action: #selector(connected(sender:)), for: .touchUpInside)
return cell
}
#objc func connected(sender: UIButton){
delegate?.sharePressed(cell: self)
}
code for viewcontroller: when i press sharePressed getting only collectionview's first cell value.. how to get all cells value.. please do let me know
class ViewMyAppliedReqVC: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, CustomCellDelegate{
func sharePressed(cell: ProposalTableVIewCell) {
guard let index = tableView.indexPath(for: cell)?.row else { return }
let name = getBitDetails?.result?.bid?.get_attachments?[index].filename// always getting only first cell value
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewProposalTableVIewCell1", for: indexPath) as! ViewProposalTableVIewCell1
cell.bidAttatchment = getBitDetails?.result?.bid?.get_attachments
cell.delegate = self
cell.attetchmentsCollectionview.reloadData()
return cell
}
You are always getting same index because you are taking out index of "ProposalTableVIewCell" and this is tableView cell. And collectionView cells are in the same tableView cell.
Solution:
Take another parameter in protocol function like below for storing index of collection cell
protocol CustomCellDelegate: class {
func sharePressed(cell: ProposalTableVIewCell,collectionCellIndex:Int)
}
func sharePressed(cell: ProposalTableVIewCell, collectionCellIndex:Int) {
guard let index = tableView.indexPath(for: cell)?.row else { return }
let name = getBitDetails?.result?.bid?.get_attachments?[collectionCellIndex].filename// This will return index of collection cell
}
#objc func connected(sender: UIButton){
delegate?.sharePressed(cell: self,collectionCellIndex: sender.tag )
}

How to Navigate to new View Controller from collection view cell? In Swift

I have two View controllers(VC-1, VC-2).
View controller 1 is having a table view and further that table view is consists of 4 collection views. I want to navigate to new VC(VC-2). But unable to get "self.storyboard.instantiateViewController" in didSelect method of collection View.
So now how I can navigate to VC-2
You should use delegate. you can create a protocol and define a method for routing and implement it into VC1
You can use the below sample code.
This code is using closure syntax
class FirstVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell_Identifier") as! TableCell
cell.configureCell(data: ["Your", "Data"])
cell.didSelectRow = { data in
// Goto second view controller
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC")
self.navigationController?.pushViewController(vc!, animated: true)
}
return cell
}
}
class TableCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var colView: UICollectionView!
var didSelectRow: ((_ data: String) -> Void)? = nil // Closure
var arrData = [String]()
func configureCell(data: [String]) {
// Setup CollectionView data
self.arrData = data
self.colView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.arrData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CELL_IDENTIFIER", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let data = self.arrData[indexPath.row]
didSelectRow?(data)
}
}

Receiving an error of when trying to add text to a label in a collection view

I am trying to input the arrayOfValues[indexPath.item] as the text for my textLabel in the collection view, but receive an error when I run the program saying 'Fatal error: Index Out of Range'
How would I fix this so that the collectionView cells are populated with information from the arrayOfValues?
Here is the code.
import UIKit
class NetworkViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var firstCollectionView: UICollectionView!
#IBOutlet weak var secondCollectionView: UICollectionView!
let arrayOfOrganizations = ["My Network", "Find Connections", "ss"]
let arrayOfValues = [""]
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (collectionView == secondCollectionView) {
return arrayOfOrganizations.count
}
return arrayOfValues.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let firstCell = firstCollectionView.dequeueReusableCell(withReuseIdentifier: "firstCell", for: indexPath) as! FirstCollectionViewCell
firstCell.textLabel.text = arrayOfValues[indexPath.item] //error on this line
if (collectionView == secondCollectionView) {
let secondCell = secondCollectionView.dequeueReusableCell(withReuseIdentifier: "secondCell", for: indexPath) as! SecondCollectionViewCell
secondCell.backgroundColor = .black
return secondCell
}
return firstCell
}
}
class FirstCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var textLabel: UILabel!
}
class SecondCollectionViewCell: UICollectionViewCell {
}
The problem you had was the the first two lines of your cellForItemAt function were getting executed no matter the collectionView. So, essentially, you need to make sure the block of code corresponding to the firstCollectionView gets executed only when collectionView == firstCollectionView, and same goes for the secondCollectionView. In short, you just need to change your function to this instead:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (collectionView == secondCollectionView) {
let secondCell = secondCollectionView.dequeueReusableCell(withReuseIdentifier: "secondCell", for: indexPath) as! SecondCollectionViewCell
secondCell.backgroundColor = .black
return secondCell
} else {
let firstCell = firstCollectionView.dequeueReusableCell(withReuseIdentifier: "firstCell", for: indexPath) as! FirstCollectionViewCell
firstCell.textLabel.text = arrayOfValues[indexPath.item] //error on this line
return firstCell
}
}

passing image from collectionViewCell which is located tableviewCell

I ask for help with determining the right approach
when I click on the picture I need to pass text and her to new VC, but the problem is that the project has a great depth struct
the cell lies in the collectionView, which is in the tableViewCell
How do I properly implement the transfer?
(the number of cells is generated automatically)
Another complication is that the code of the cell with which I work lies in another cell.
those. the transfer of information must also be written in it.
import UIKit
import moa
class RealPhotoInfoTableViewCell: UITableViewCell {
#IBOutlet private weak var MyCollection: UICollectionView!
var model: RealPhoto!
func setCollectionViewDataSourceDelegate(dataSourceDelegate: UICollectionViewDataSource & UICollectionViewDelegate, forRow row: Int) {
MyCollection.delegate = self
MyCollection.dataSource = self
MyCollection.reloadData()
}
}
extension RealPhotoInfoTableViewCell: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(model?.data.count as Any)
return model?.data.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RPhotoCell", for: indexPath) as! RealPhotoCollectionViewCell
cell.realPhotoImage.moa.url = model?.data[indexPath.row].photo
return cell
}
}
Add a var
class RealPhotoInfoTableViewCell: UITableViewCell {
weak var delegate:VCName?
Inside cellForRowAt of the table do
cell.delegate = self
Now you can do this inside didSelectItemAt of the collection
delegate?.sendData(image)
You have two options:
One is Sh_Khan answer using delegation.
Or you can use Notification observers.
This question has been asked before...
You can use delegate protocol in that case. You can implement that protocol. Please find following sample code for that.
protocol ImageSelectionDelegate {
func imageClicked(imageURL: String)
}
//Class A
class A : ImageSelectionDelegate{
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//your existing code
cell.delegate = self
}
//Implement that protocol
func imageClicked(imageURL: String){
//You will get url for tapped image
}
}
class RealPhotoInfoTableViewCell{
weak var delegate : ImageSelectionDelegate? = nil
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate.imageClicked(model?.data[indexPath.item].photo)
}
}

pass data from UITableViewCell to UIViewController

I have UITableViewCell and I want to send the indexPath.row number to UIViewController using didSet, but xcode gives me an error when i use the value for other things (in UIViewController) says that the value is nil error: unexpectedly found null when unwrapping an optional value.
But if I print in the variable in UIViewController the value appears.
What i do? Thanks.
class TableViewCellCentral: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var CollectionData: UICollectionView!
var send = Int() {
didSet{
ViewController().reload = send
}
}
override func awakeFromNib() {
super.awakeFromNib()
CollectionData.dataSource = self
CollectionData.delegate = self
CollectionData.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
cell.LabelData.text! = "number \(indexPath.row)"
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
send = indexPath.row
CollectionData.reloadData()
}
}
ViewController() is just an instance of your ViewController. What you're doing when you say ViewController() is you're creating a new ViewController, rather than accessing the one you're looking for. If you want the indexPath.row, you need to send it to the actual VC, not just an instance of it.
You need to keep in mind that not all data is loaded instantly and at the same time, also that it does not always load in the order that you expect it to. It is possible that you are asking for the data before it is even assigned. Try
import UIKit
class TableViewCellCentral: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var CollectionData: UICollectionView!
var send = Int() {
didSet {
ViewController().reload = send
}
}
override func awakeFromNib() {
super.awakeFromNib()
CollectionData.dataSource = self
CollectionData.delegate = self
CollectionData.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
if indexPath.row != nil {
cell.LabelData.text! = "number \(self.indexPath.row)"
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
send = indexPath.row
CollectionData.reloadData()
}
}
I am only printing if the value is not nil! Let me know if you have more questions, or let us know if my solution is not working. =)