Dismissal Error - ios

I have a setup that brings up a date picker upon clicking of a button. I have two a function that changes the value of a button upon selecting a date. In addition, I also have a function that should help dismiss the date picker when I press the done button. However, I continue to get an error stating 'unrecognized selector sent to instance'. Any idea what I could have possibly done wrong
#IBOutlet weak var dueDateSelector: UIButton!
#IBOutlet weak var myPickerView: UIPickerView!
#IBAction func changeDueDate(_ sender: Any) {
//Create the view
let inputView = UIView(frame: CGRect(x:0, y:420, width: self.view.frame.width, height: 240))
var datePickerView : UIDatePicker = UIDatePicker(frame: CGRect(x:0, y:40, width:0, height:0))
datePickerView.datePickerMode = UIDatePickerMode.date
inputView.addSubview(datePickerView) // add date picker to UIView
let doneButton = UIButton(frame: CGRect(x:270, y:0, width:100, height:50))
doneButton.setTitle("Done", for: UIControlState.normal)
doneButton.setTitle("Done", for: UIControlState.highlighted)
doneButton.setTitleColor(UIColor.black, for: UIControlState.normal)
doneButton.setTitleColor(UIColor.gray, for: UIControlState.highlighted)
inputView.addSubview(doneButton) // add Button to UIView
doneButton.addTarget(self, action: "doneButton:", for: UIControlEvents.touchUpInside) // set button click event
datePickerView.addTarget(self, action: Selector("handleDatePicker:"), for: UIControlEvents.valueChanged)
view.addSubview(inputView)
handleDatePicker(sender: datePickerView) // Set the date on start.
}
#objc func handleDatePicker(sender: UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
dueDateSelector.setTitle(dateFormatter.string(from: sender.date), for: .normal)
}
#objc func doneButton(sender:UIButton)
{
dueDateSelector.resignFirstResponder() // To resign the inputView on clicking done.
}

This is due to an inconsistency in naming methods between Swift and Objective C. This is also why you should write selectors with the #selector syntax instead of using strings. You need to change this line:
datePickerView.addTarget(self, action: Selector("handleDatePicker:"), for: UIControlEvents.valueChanged)
Selectors are an Objective C thing. If you write it in strings, then you need to write it in an Objective C fashion. In your code, handleDatePicker is not actually called handleDatePicker: in Objective C. It is probably something like handleDatePickerWithSender:. This is because you have a sender argument there, and that becomes the WithSender part in the eyes of Objective C.
This is why we like to write selectors like this:
#selector(handleDatePicker)
No need to worry about parameters, just the method name.
datePickerView.addTarget(self, action: #selector(handleDatePicker), for: UIControlEvents.valueChanged)
Also, this line needs to be changed as well:
doneButton.addTarget(self, action: "doneButton:", for: UIControlEvents.touchUpInside)
It should be:
doneButton.addTarget(self, action: #selector(doneButton), for: UIControlEvents.touchUpInside)

I think you are having problem here,
#objc func doneButton(sender:UIButton)
{
dueDateSelector.resignFirstResponder() // To resign the inputView on clicking done.
}
here dueDateSelector is button which is not having any method called resignFirstResponder() so that's why you are getting error
instead you can do this,
#objc func doneButton(sender:UIButton)
{
//remove or hide the input view
}
You can also check that whether current component having this method or not with,
if dueDateSelector.canResignFirstResponder()
{
}

You are using deprecated string selector syntax:
doneButton.addTarget(self, action: "doneButton:", for: UIControlEvents.touchUpInside)
Should be replaced with:
doneButton.addTarget(self, action: #selector(doneButton(sender:)),
for: .touchUpInside)
It's also applied to the other method in your code:
datePickerView.addTarget(self, action: #selector(handleDatePicker(sender:)),
for: .valueChanged)

doneButton.addTarget(self, action:#selector(self.doneButton(_:)) , for:
UIControlEvents.touchUpInside) // set button click event
datePickerView.addTarget(self, action: #selector(self.handleDatePicker(_:)), for: UIControlEvents.valueChanged)
if self wont work use class reference like yourClass().doneButton

Related

Action of UIButton doesn't work if the button is initialized with let and the addTarget in it in custom view, but it works in UIViewController

When I create a button like below in the custom view the action does not work:
private let usernameButton: UIButton = {
let button = UIButton(type: .system)
button.setTitleColor(.black, for: .normal)
button.setTitle("someTitle", for: .normal)
button.titleLabel?.font = .boldSystemFont(ofSize: 13)
button.addTarget(self, action: #selector(didTapUsername), for: .touchUpInside)
return button
}()
However, it works when I do the same in UIViewController somehow.
It always works if I make it lazy var but couldn't understand why it doesn't work if I make it let in custom view while It is working in UIViewController
Thanks for any comment.
self inside that block actually is the block, not the view(you can see it using print(self)), probably because it's not yet initialised(same reason why you can't use self before super.init), that's why I usually add targets/delegates outside of the initialisation block. With lazy var self is already initialised, so no problem should be there.
I'm not sure why it works at all, seems kind of magic for me, and I wouldn't depend on it.
Anyway, it works fine with both custom ViewController and custom View in my case: I've added CustomView as subview to ViewController in the storyboard.
class ViewController: UIViewController {
private let usernameButton: UIButton = {
let button = UIButton(type: .system)
button.setTitleColor(.black, for: .normal)
button.setTitle("someTitle", for: .normal)
button.titleLabel?.font = .boldSystemFont(ofSize: 13)
button.addTarget(self, action: #selector(didTapUsername), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.insertSubview(usernameButton, at: 0)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
usernameButton.frame = view.bounds
}
#objc
func didTapUsername() {
print("ViewController", #function)
}
}
class CustomView: UIView {
private let usernameButton: UIButton = {
let button = UIButton(type: .system)
button.setTitleColor(.black, for: .normal)
button.setTitle("someTitle", for: .normal)
button.titleLabel?.font = .boldSystemFont(ofSize: 13)
button.addTarget(self, action: #selector(didTapUsername), for: .touchUpInside)
return button
}()
override func awakeFromNib() {
super.awakeFromNib()
addSubview(usernameButton)
}
override func layoutSubviews() {
super.layoutSubviews()
usernameButton.frame = bounds
}
#objc
func didTapUsername() {
print("CustomView", #function)
}
}
This shouldn't do differently for UIViewController/UIView, check out your logic

Adding a target to button inside a closure doesn't work

The following code is located inside a subclass of UIView
I am setting up a cancelButton inside a closure:
private var cancelButtonClosure: UIButton = {
...
button.addTarget(self, action: #selector(cancel(_:)), for: .touchUpInside)
...
}()
And at first I instantiated the button inside a function like so:
func showConfirmationView(...) {
...
let cancelButton = self.cancelButtonClosure
...
addSubview(cancelButton)
...
}
However this resulted in the cancel function not being called at all (even though the layout was right and the button was highlighting)
So I made these change:
Removed the addTarget part from the cancelButtonClosure
Added the addTarget part inside the showConfirmationView function
So it looked like that:
func showConfirmationView(...) {
...
let cancelButton = self.cancelButtonClosure
cancelButton.addTarget(self, action: #selector(cancel(_:)), for: .touchUpInside)
...
addSubview(cancelButton)
...
}
It worked: the cancel function was called; but I don't know why. I'm really curious to know why what I did before did not work. Thanks for your insights!
Check your implementation because a setup like this works as expected:
private var cancelButton: UIButton = {
let btn = UIButton(type: .system)
btn.setTitle("Cancel", for: .normal)
btn.addTarget(self, action: #selector(cancelSomething(_:)), for: .touchUpInside)
return btn
}()
#objc func cancelSomething(_ sender: UIButton) {
print("Something has to be cancelled")
}
override func viewDidLoad() {
super.viewDidLoad()
showConfirmationView()
}
func showConfirmationView() {
cancelButton.sizeToFit()
cancelButton.center = view.center
view.addSubview(cancelButton)
}

UIButton addTarget Selector is not working

SquareBox.swift
class SquareBox {
func createBoxes() {
for _ in 0..<xy {
let button = UIButton()
button.backgroundColor = .white
button.setTitleColor(UIColor.black, for: .normal)
button.layer.borderWidth = 0.5
button.layer.borderColor = UIColor.black.cgColor
stack.addArrangedSubview(button)
button.addTarget(self, action: #selector(click(sender:)) , for: .touchUpInside)
}
}
#objc func click(sender : UIButton) {
print("Click")
}
}
ViewController.swift
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let boxRow = SquareBox()
boxRow.createBoxes()
}
}
Also I've tried #IBAction instead of #objc, it doesn't work, but if I use "click" function in ViewController.swift that I created this object, it's working but I need this function inside of this class.
Now that you have posted relevant information in your question, the problem is quite clear. You have a memory management issue.
In your GameViewController's viewDidLoad you create a local instance of SquareBox. This local instance goes out of scope at the end of viewDidLoad. Since there is no other reference to this instance, it gets deallocated at the end of viewDidLoad.
Since the instance of SquareBox has been deallocated, it is not around to act as the button's target. And your click method is never called.
The solution is to keep a reference in your view controller:
class GameViewController: UIViewController {
let boxRow = SquareBox()
override func viewDidLoad() {
super.viewDidLoad()
boxRow.createBoxes()
}
}
var btnfirst:UIButton!
override func viewDidLoad()
{
super.viewDidLoad()
btnfirst = UIButton(type: .system)
btnfirst.setTitle("Press", for: .normal)
btnfirst.setTitleColor(.red, for: .normal)
btnfirst.frame = CGRect(x: 100, y: 200, width: 100, height: 30)
btnfirst.addTarget(self, action: #selector(benpress( sender:)),for: .touchUpInside)
self.view.addSubview(btnfirst)
}
func benpress( sender :UIButton)
{
//Your Code Here
}
For those who did not find a solution, here is mine.
If you constructed your UIButton as
let button: UIButton = {
return UIButton()
}()
Just convert those into
lazy var button: UIButton = {
return UIButton()
}()
I think this is because of somewhat deallocation as mentioned above.
button.addTarget(self, action:#selector(self.click), for: .touchUpInside)
func click(sender : UIButton) {
// code here
}
I guess the issue is how you are setting up layout of your buttons.
Try this:
func createBoxes() {
stack.backgroundColor = UIColor.red
for _ in 0..<xy {
// Create the button
let button = UIButton()
button.backgroundColor = UIColor.red
// Add constraints
button.translatesAutoresizingMaskIntoConstraints = false
button.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
button.widthAnchor.constraint(equalToConstant: 44.0).isActive = true
// Setup the button action
button.addTarget(self, action: #selector(SquareBox.click(sender:)), for: .touchUpInside)
// Add the button to the stack
stack.addArrangedSubview(button)
}
}
#objc func click(sender : UIButton) {
print("Click")
}
button.addTarget(self, action: #selector(self.buttonTapped), for: .touchUpInside)
func buttonTapped(sender : UIButton) {
// code here
}
Replace with this :
btn.addTarget(self, action: #selector(self.click(sender:)), for: .touchUpInside)
I think something else effect to your selector method try to find in your code because your code also working in my project.

Xcode 7 swift, ''no method declared with objective-c selector (function)" warning

I want to add an action to a button, but I heard that the code below does not work. Does anyone know the way to add an action to a button.
button.addTarget(self, action: Selector("function:"), forControlEvents: .TouchUpInside)
Here is the code
I am using Xcode 7.3.1
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRectMake(100, 80, 30, 30))
func pressed(sender: UIButton!) {
print("button pressed")
}
button.backgroundColor = UIColor.redColor()
button.addTarget(self, action: #selector(pressed(_:)), forControlEvents: .TouchUpInside)
self.view.addSubview(button)
}
I'm guessing that your problem is with the Selector part.
In Swift 2.2 the selector syntax was changed so you now get a compile time check for your selectors. You can read more about that here.
To answer your question, this syntax:
button.addTarget(self, action: #selector(function(_:)), forControlEvents: .TouchUpInside)
should make you and - more importantly in this case (sorry :)) - the compiler happy.
Update (after looking at the code you provided)
You need to move the pressed function outside of your viewDidLoad function so that it is a separate function.
So your code ends up looking like this:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRectMake(100, 80, 30, 30))
button.backgroundColor = UIColor.redColor()
button.addTarget(self, action: #selector(pressed(_:)), forControlEvents: .TouchUpInside)
self.view.addSubview(button)
}
func pressed(sender: UIButton) { //As ozgur says, ditch the !, it is not needed here :)
print("button pressed")
}
And that seems to work, I can see button pressed in my console now at least.
Hope that helps you.
Try These
button.addTarget(self, action: #selector(buttonAction), forControlEvents: UIControlEvents.TouchUpInside)
your method
func buttonAction (sender:UIButton)
{
}

Why do I get signal SIGABRT when I select a created button?

I'm creating a button in swift 2 and when I select it, I get signal SIGABRT and the app crashes. Heres the code:
let button = UIButton()//(type: UIButtonType.System) as UIButton!
button.setTitle("button", forState: .Normal)
button.setTitleColor(UIColor.blueColor(), forState: .Normal)
button.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
button.frame = CGRectMake(100, 100, 100, 100)
self.view.addSubview(button)
func buttonPressed(sender: UIButton!) {
print("ButtonIsSelected")
}
It brings me to AppDelegate.swift and in the middle of the NSLog it says: unrecognized selector sent to instance...
Please help. Anton
func buttonPressed(sender: UIButton!) {
print("ButtonIsSelected")
}
This method must be in your class body not in function body . As I guess you have done.

Resources