UIButton inside a custom input view doesn't invoke any methods - ios

I created a custom input view with a couple of UIButtons inside it. All these buttons invoke one single IBAction.
The IBAction is not called although I'am 100% sure I set them properly in IB. To prove that this isn't causing the problem I added a target to one of the buttons programmatically, but the action still won't get invoked.
import UIKit
protocol CashDeskInputDelegate: class {
func didReceiveInput(inputValue: String)
func didReceiveDoneMessage()
}
class CashDeskInputViewController: UIInputViewController {
// Delegate
weak var delegate: CashDeskInputDelegate?
// Actions
#IBAction func buttonTapped(sender: UIButton) {
print("buttonTapped")
guard let valueOfSender = sender.titleLabel?.text else {
dismissKeyboard()
return
}
valueOfSender == "Done" ? delegate?.didReceiveDoneMessage() : delegate?.didReceiveInput(valueOfSender)
}
// Test outlet
#IBOutlet weak var firstButton: UIButton!
override func viewDidLoad() {
// Add an action to the first button for testing purposes.
firstButton.addTarget(self, action: "buttonTapped:", forControlEvents: .TouchUpInside)
}
}
I didn't implement the delegate properly yet, but that not the the point. The print("buttonTapped") won't even show up. The method just doesn't get called, I tested this using breakpoints.
Does anyone know what is causing this problem

Related

How to select a UITextField with IBAction to make it FirstResponder?

I have implemented multiple TextFields in a static TableViewController like this:
import UIKit
class GameViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var inputField11:UITextField?
#IBOutlet weak var inputField12:UITextField?
...
override func viewDidLoad() {
super.viewDidLoad()
inputField11!.delegate = self
inputField12!.delegate = self
...
inputField11?.becomeFirstResponder()
}
}
I can't seem to find a way to implement a way to change the active TextField with an IBAction.
I have an inputFieldDidChange IBAction method implemented that works fine, triggered by "Editing Changed" in the storyboard:
#IBAction func inputFieldDidChange(inputField: UITextField?) {
switch inputField {
case inputField11:
inputField12?.becomeFirstResponder()
case inputField12:
inputField13?.becomeFirstResponder()
...
}
But for some reason the same implementation method doesn't work for my inputFieldSelected method, triggered by "Touch Down":
#IBAction func inputFieldSelected(inputField: UITextField?) {
switch inputField {
case inputField11:
inputField11?.becomeFirstResponder()
case inputField12:
inputField12?.becomeFirstResponder()
...
}
}
I also tried doing this with "Touch Up Inside", "Editing Did Begin" and tap gesture recognizers.

Why does UIImageView.image need to be set using a DispatchQueue.main.async even on the main thread

Trying to set an image on a button when tapped. Verified that the targetAction handler is always invoked on the main thread.
This doesn't work
#objc func buttonTapped() {
self.mybutton.imageView?.image = MyObjcClass.getImageNamed("DarkVersion")
}
But this works:
#objc func buttonTapped() {
DispatchQueue.main.async { // Does not work without this dispatch
self.mybutton.imageView?.image = MyObjcClass.getImageNamed("DarkVersion")
}
}
On the debugger I can see that both are on the main thread
Correct way to set an image to a button is using of setImage(_ image: UIImage?,for state: UIControl.State) method.
When you use direct access to set image, the button does not know about it and change the set image in state changing routine.
Really you do not need to change image in buton's action method, you just need
set images for states and to change a state of the button in this method. Button'll pick appropriate image for state.
The correct code from the view controller should be:
class ViewController: UIViewController {
#IBOutlet weak var myButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(buttonTapped))
myButton.addGestureRecognizer(tapGesture)
}
#objc func buttonTapped() {
self.myButton.setImage( MyObjcClass().getImageNamed("DarkVersion"), for: .normal)
}
}
Which works without fail, the difference is that setImage is used to set the image.

Issue calling externally assigned closure from IBAction

I have this UIView subclass:
class EmptyAlbumsView: UIView {
class func instanceFromNib() -> EmptyAlbumsView {
return R.nib.emptyAlbumsView.firstView(owner: nil)! as EmptyAlbumsView
}
// MARK: - IBActions
#IBAction func didTapFreeAlbumButton(sender: UIButton) {
print("Tapping button")
print(didTapFreeAlbumButtonClosure)
didTapFreeAlbumButtonClosure?()
}
#IBAction func didTapEventAlbumButton(sender: UIButton) {
didTapEventAlbumButtonClosure?()
}
#IBAction func didTapWhatsTheDifferenceButton(sender: UIButton) {
didTapWhatsTheDifferenceButtonClosure?()
}
#IBAction func didTapSubmitAlbumCodeButton(sender: UIButton) {
didTapSubmitAlbumCodeButtonClosure?()
}
// MARK: - Public Properties
open var didTapFreeAlbumButtonClosure: EmptyClosure? {
didSet {
log.verbose("set to \(self.didTapFreeAlbumButtonClosure!)")
}
}
open var didTapEventAlbumButtonClosure: EmptyClosure?
open var didTapWhatsTheDifferenceButtonClosure: EmptyClosure?
open var didTapSubmitAlbumCodeButtonClosure: EmptyClosure?
}
which I am initialising in a UIViewController as such:
fileprivate func showEmptyAlbumsView() {
let emptyAlbumsView = EmptyAlbumsView.instanceFromNib()
emptyAlbumsView.didTapFreeAlbumButtonClosure = {
print("hey")
}
view.addSubview(emptyAlbumsView)
emptyAlbumsView.matchEdgeAnchorsOfView(self.view)
}
I can see the Tapping button log statement from IBAction, but the second log statement over there prints nil, as it appears the didTapFreeAlbumButtonClosure has not been set, and of course not getting called ever. I never see hey printed out.
However, in the didSet block I can clearly see the closure is getting set.
EmptyClosure is defined as typealias EmptyClosure = () -> ()
What am I missing here?
Ok, after a lot of frustration, the problem was rather silly.
In the Interface Builder I had set the File Owner of the my xib to EmptyAlbumsView. That was causing the IBActions to be called properly but when I tried hooking up some IBOutlets I was getting KVC errors.
It appears the proper way to do this is leave the File Owner class empty, and set the root views of the xib to EmptyAlbumsView. Then I'd hook my IBOutlets and IBActions directly to the view.

UITapGestureRecognizer is not being recognized

In my storyboard I have a basic view, with a login field. In the storyboard the checkbox for Enable user interaction is checked, and I am also settings this through the code.
Below is the code I'm using for this:
class LoginViewController : UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
override func viewDidLoad() {
super.viewDidLoad();
let closeKeyboardGesture = UITapGestureRecognizer(target: self, action: "dismissKeyboard");
self.view.userInteractionEnabled = true
self.view.addGestureRecognizer(closeKeyboardGesture);
}
private func dismissKeyboard() {
print("Called")
if passwordField.selected {
passwordField.resignFirstResponder()
}
if emailField.selected {
emailField.resignFirstResponder()
}
}
}
As you can see it's fairly straightforward, however the dismissKeyboard function is never called. What bothers me is I'm using these gestures elsewhere in my application and they're working fine.
That´s because you have your dismissKeyboard function marked as private. If you are calling a method from a selector and it is private they cannot be called because the method is called from outside.
So remove private from dismissKeyboard and it will work.
Update
If you change the above it will work, what´s not working for you right now is the resignFirstResponder You don´t need to the if-checks since you always want to hide the keyboard when you active the closeKeyboardGesture, so it´s enough to only call self.view.endEditing(true). I have created a sample project for you that has a working example. You can download it from here.
func dismissKeyboard() {
view.endEditing(true)
}
This will do the trick.

Swift: how to use UISwitch to control UITextField to be enabled or disabled with a delegate

In XCode 6.3.2, I have a UITextField:
#IBOutlet weak var uiswitchControlledTextField: UITextField!
I am now using a UISwitch (named mySwitch) to control its enabled or disabled state in the following way:
#IBOutlet weak var mySwitch: UISwitch!
mySwitch.addTarget(self, action: Selector("stateChanged:"), forControlEvents: UIControlEvents.ValueChanged)
//callback below:
func stateChanged(switchState: UISwitch) {
uiswitchControlledTextField.enabled = switchState.on
}
The above works well, however, I am looking to try if it would be possible to create a UITextFieldDelegate to control the above UITextField in the same way. So far, I have the following by implementing textFieldShouldBeginEditing, in which I wish to return false to disable the UITextField, but I don't know how to let the UISwitch dynamically return true or false from textFieldShouldBeginEditing
import Foundation
import UIKit
class SwitchControlledTextFieldDelegate: NSObject, UITextFieldDelegate {
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
return false; //do not show keyboard or cursor
}
}
In ViewController, I try to set
self.uiswitchControlledTextField.delegate = SwitchControlledTextFieldDelegate()
but it does not work as I wished. Any help would be appreciated.
self.uiswitchControlledTextField.delegate = SwitchControlledTextFieldDelegate()
The problem is that that line merely creates an instance of your SwitchControlledTextFieldDelegate class, which then immediately goes right back out of existence.
You need to use, as your text field delegate, some instance which already exists and which will persist - like, perhaps, your view controller!
(Xcode 7)
Use this:
override func viewDidLoad() {
super.viewDidLoad()
// Setting the delegate
self.textField3.delegate = self
self.editingSwitch.setOn(false, animated: false)
}
// Text Field Delegate Methods
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
return self.editingSwitch.on
}
#IBAction func toggleTheTextEditor(sender: AnyObject) {
if !(sender as! UISwitch).on {
self.textField3.resignFirstResponder()
}
}

Resources