Unrecognized selector sent to instance in UIButton - ios

I have a collection view and image view inside it and I added a UIButton to delete the image after selection. When I click the button it crashes and gives me this error:
AdPostViewController deleteUser]: unrecognized selector sent to instance 0x7fb588d5b7f0
Why is this happening and how do I fix this? Here is my code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! ImageCell
let img = self.PhotoArray[indexPath.row]
cell.image.image = img
cell.deleteButton?.layer.setValue(indexPath.row, forKey: "index")
cell.deleteButton?.addTarget(self, action: Selector(("deleteUser")), for: UIControl.Event.touchUpInside)
return cell
}
func deleteUser(_ sender: UIButton) {
let i: Int = (sender.layer.value(forKey: "index")) as! Int
PhotoArray.remove(at: i)
// PhotoArray.removeAtIndex(i)
ImagesCollectionView.reloadData()
}

One problem is that you are forcing manual formation of the Objective-C selector, and you don't actually know how to form an Objective-C selector manually so you are getting it wrong. Don't do that! Let the compiler form the selector for you. That's its job. Replace
action: Selector(("deleteUser"))
with
action: #selector(deleteUser)
Also, you need to expose your deleteUser method to Objective-C explicitly:
#objc func deleteUser(_ sender: UIButton) {
Otherwise Objective-C still won't be able to introspect your class and find this method when the time comes to call it. Fortunately, when you switch to #selector syntax, the compiler will call out that issue for you!

Related

Button add target function not called in CollectionView cell

I have a collection view where each of the cells has a delete button. I added the following code to cellForItemAt indexPath function.
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellTwo", for: indexPath) as! CustomCellTwo
cell.deleteButton.layer.setValue(indexPath.row, forKey: "index")
cell.deleteButton.addTarget(self, action: #selector(deleteCell), for: .touchUpInside)
Initially it looked as if it was working great. However, I found out that the add target function does not get called at the first tap if I scroll back and forth and then tap the delete button. If I tap again, it works as expected. Only the first tap does not work.
I have been trying to find a reason and a solution for several hours... Please help provide any ideas and advice.
Try to move buttons handling into CustomCellTwo implementation. Handle button event touchUpInside with #IBAction func. Now you can debug it with breakpoint set in this function's body.
Also add closure type variable to your CustomCellTwo to pass deleteCell calls into it. So it could also be checked with breakpoint.
Example:
class CustomCellTwo: UICollectionViewCell {
var onDelete: (() -> Void)?
#IBAction func onDeleteButtonTouch(_ sender: Any) {
onDelete?()
}
}
// in your UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellTwo", for: indexPath) as! CustomCellTwo
cell.onDelete = {
self.deleteCell(indexPath)
}
}

UIButton within UITableViewCell issue: can't get recognized selector

So I've been searching StackExchange on how to put a UIButton inside of a UITableViewCell and thought I found the answer, but keep getting an "unrecognized selector sent to instance" error.
Here's where I call the function
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tblTeams.dequeueReusableCell(withIdentifier: "cellReuse")! as! TeamsTableViewCell
cell.btnLeave.tag = indexPath.row
cell.btnLeave.addTarget(self, action: "LeaveTeam:", for: UIControlEvents.touchUpInside)
return cell
}
and here's where the function is. It's within the same class, and even extension, as the prior code block
#IBAction func LeaveTeam(sender: UIButton){
}
I've tried rewording the quote, I've tried using #selector... just please tell me how I do it right. Thanks!
Replace
cell.btnLeave.addTarget(self, action: #selector(leaveTeam(_:)) for: UIControlEvents.touchUpInside)
#objc func leaveTeam(_ sender: UIButton) {---}
start method name in lower case
addTarget(self, action:#selector(leaveTeam(sender:)), for: .touchUpInside)
#objc func leaveTeam(sender : UIButton) -> Void {
}

Swift 3 adding selector issue on cell button

I have a custom button in my collection view cell. I just want to pass indexPath to it but I am getting
"unrecognized selector error"
Here is my code
cell.showMapButton.addTarget(self, action: #selector(testFunc(indexPath:)), for: .touchUpInside)
and the function is
func testFunc(indexPath: IndexPath){
print("Testing indexPath \(indexPath)")
}
If I remove the indexPath argument it works fine and the function gets called but I need that argument so please help me in resolving this issue.
In the addTarget(:action:for:) method for UIButton, the action can at most accept a single UIButton or any of it's superclass as parameter. If you need the indexPath of your button, you need to make it a property of your UIButton by subclass or other means. My way of doing it is to create a subclass of UIButton that have indexPath as it's property:
class ButtonWithIndexPath: UIButton {
var indexPath:IndexPath?
}
Then add target as normal:
cell.showMapButton.addTarget(self, action: #selector(testFunc(button:)), for: .touchUpInside)
Not forgetting to set the indexPath of your button to that of which ever cell it is in
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath) as! myCell
cell.button.indexPath = indexPath
...
return cell
}
And cast it into it's custom subclass in the function to read the indexPath:
func textFunc(button: UIButton) {
let currentButton = (button as! ButtonWithIndexPath)
print(currentButton.indexPath)
}
You can pass UIButton instance with target selector parameters for button action.
try with following code:
Add/replace below code, belongs to collection view cell into your collection view data source method - cellForRowAtIndexPath
cell.showMapButton.tag = indexPath.row
cell.showMapButton.addTarget(self, action: #selector(testFunc(button:)), for: .touchUpInside)
For Swift 4 - define your selector function using #objc, like below.
#objc func testFunc(button: UIBUtton){
print("Index = \(button.tag)")
}

UIButton unrecognized selector sent to instance [duplicate]

This question already has answers here:
UIButton causing unrecognized selector sent to instance
(5 answers)
Closed 5 years ago.
I am using a custom cell with UICollectionView, I need to define UIButton programmatically per cell.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! ClinicListCell
cell.title.text = clinicNames[indexPath.row]
cell.subTitle.text = clinicSubs[indexPath.row]
cell.backgroundImageView.image = UIImage(named: clinicImages[indexPath.row])
cell.profileBtn.tag = indexPath.row
cell.profileBtn.addTarget(self, action: Selector(("profileBtnClicked:")), for: .touchUpInside)
return cell
}
And I have defined the following selector method in the same class.
class func profileBtnClicked(sender:UIButton) {
print("Selected")
}
I've tried by removing class/static from the selector method, but it always give me unrecognized selector sent to instance error, where am I going wrong?
Thanks.
Try this
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! ClinicListCell
cell.title.text = clinicNames[indexPath.row]
cell.subTitle.text = clinicSubs[indexPath.row]
cell.backgroundImageView.image = UIImage(named: clinicImages[indexPath.row])
cell.profileBtn.tag = indexPath.row
cell.profileBtn.addTarget(self, action: #selector(YourViewController.profileBtnClicked(sender:)), for: UIControlEvents.touchUpInside)
return cell
}
class func profileBtnClicked(sender:UIButton) {
print("Selected")
}
Is the profileBtn linked up probably? This error may happens when the name has changed or the link between the button in interface builder and the variable is removed.
Or you can try with the syntax
cell.profileBtn.addTarget(self, action: #selector("profileBtnClicked:"), for: .touchUpInside)
Try adding a #objc to your method, not strictly required in this case, and remove the class or static qualifier.
By the way, since Swift 2.2, you can create a Selector from a Swift function using the #selector operator. For instance:
let clicked = #selector(self.profileBtnClicked(sender:))
for:
#objc func profileBtnClicked(sender: UIButton) {
...
}
Technically, for NSObject based classes, the #obj qualifier should only be required for private methods.

selector for button inside collectionView cell

This is driving me nuts, I've been reading SO for hours and tried everything and cant get this button selector to work. This shouldn't be difficult.
Inside CellForItemAt i have set the button tag and try call the button.
cell.deleteCellButton.tag = indexPath.item
cell.deleteCellButton.addTarget(self, action: #selector(deleteCellButtonTapped(sender:)), for: UIControlEvents.touchUpInside)
I've tried (_:), "deleteCellButtonTapped:", and any other number of parenthesis combinations and i still get unrecognised selector. i don't know why autocomplete recommends (sender:) I've never seen this before.
then my button function:
func deleteCellButtonTapped(sender: UIButton!) {
self.packArray.remove(at: sender.tag)
print(packArray.count)
self.outerCollectionView.deleteItems(at: [IndexPath(item: sender.tag, section: 0)])
self.outerCollectionView.reloadData()
self.outerCollectionView.layoutIfNeeded()
}
Assuming you're using Swift 3, and func deleteCellButtonTapped(sender: UIButton!) is in the same class:
addTarget(self, action: #selector(deleteCellButtonTapped(sender:)), for: .touchUpInside)
works fine.
Refering the selector method from it's class works for me.
What you can do is access selector method prefixing by it's class name.
I assume your class name is MyClassViewController. And you code will look like:
class MyClassViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
.... // Other implementation methods
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
....// create cell object and dequeue
cell.deleteCellButton.addTarget(self, action: #selector(MyClassViewController.deleteCellButtonTapped(_:)), for: .touchUpInside)
return cell
}
func deleteCellButtonTapped(_ sender: Any) {
// your method implementation
print("Selector method called")
}
}
Hope this works fine

Resources