Swift 2 TapGesture Error: "unrecognized selector sent to instance" - ios

I've spent 2 days trying to get a single tap to work on a single view (clicking anywhere in the screen). I've tried every variation of fixing this problem I could find. Inside the DVC Class, with #IBActions on everything, renaming the view as an #IBAction etc. I can't get any other error except : "[UIView score:]: unrecognized selector sent to instance"
class DataViewController: UIViewController, UIGestureRecognizerDelegate {
var tappy = UITapGestureRecognizer()
override func viewDidLoad() {
self.tappy = UITapGestureRecognizer(target:self.view, action:"score:")
self.tapView!.addGestureRecognizer(self.tappy)
}
}
func score(sender:UITapGestureRecognizer!) throws {
print("tapped")
}

One problem is that your action: selector, "score:", doesn't correspond to what Objective-C sees when you declare your method as func score(sender:UITapGestureRecognizer!) throws. It sees "score:error:". The simplest solution is to delete throws, since "score:error:" cannot be an action method signature for a tap gesture recognizer.
Moreover, as #dan has pointed out, score is not in self.view but in self. So you also need to change your target:.

Related

Custom tap recognizer method won’t work if implemented in other class

Is is possible create a global method accesible by any other class to add tap recognizers?
(I'm a beginner in swift)
Context/What I want to achieve:
Since I will be using a lot of tap recognizers (for labels and imageViews) in various views, I want to create a default method that helps me save a few lines of code everytime I need a tap recognizer.
-> Example of what I want
class Toolbox {
static func customTapRecognizerForLabel () {}
static func customTapRecognizerForImage () {}
}
So I can use them in different view controllers:
class ViewControllerOne{
Toolbox.customTapRecognizerForLabel()
}
class ViewControllerTwo{
Toolbox.customTapRecognizerForLabel()
}
What have I done so far?:
What didn't worked:
I created the Toolbox class in Toolbox.swift, tried to call it in other view controllers but it does not work. (Also tried to define a shared instance of the class instead of using static methods but did not worked either)
What worked:
Implementing the methods within the same view controller.
My Toolbox code:
import Foundation
import UIKit
class Toolbox: UIViewController {
static func tapRecognizerforLabel (named label: UILabel, action: Selector) {
let tapGestureForLabel = UITapGestureRecognizer(target: self, action: action)
label.addGestureRecognizer(tapGestureForLabel)
label.isUserInteractionEnabled = true
}
}
How I call it:
class ViewOne: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
Toolbox.tapRecognizerforLabel(named: nameLabel, action: #selector(self.methodAlpha))
}
func methodAlpha() {
print("It's friday my dudes")
}
}
The error I get when touching the label:
2018-07-13 11:08:22.131602-0500 MyApp[20435:1274296]
+[MyApp.Toolbox methodAlpha]: unrecognized selector
sent to class 0x1033c0038
2018-07-13 11:08:22.218289-0500 MyApp[20435:1274296]
*** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason:
'+[MyApp.Toolbox methodAlpha]: unrecognized selector
sent to class 0x1033c0038'
Why does it work if I implement the tapRecognizerforLabel() method in ViewOne class but it doesn't if I implement it in other class?
Suggestions to achieve what I want in other ways are welcome
Thank you :)
You need to send the target like this
func tapRecognizerforLabel (named label: UILabel, action: Selector,target:Any) {
let tapGestureForLabel = UITapGestureRecognizer(target:target, action: action)
label.addGestureRecognizer(tapGestureForLabel)
label.isUserInteractionEnabled = true
}
The target should contain the implementation of the method inside the selector , since you set self which is Toolbox and it doesn't contain it hence the crash happens , to call
Toolbox.tapRecognizerforLabel(named: nameLabel, action: #selector(self.methodAlpha),target:self)

How to properly use selectors in swift 4

I have read many tutorials and even the official Apple documentation and must not understand what is wrong with this code.
var dueDatePicker = UIDatePicker()
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.inputView = dueDatePicker
dueDatePicker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: UIControlEvents.valueChanged)
}
func datePickerValueChanged(_ sender: UIDatePicker){
//Do Stuff
}
At runtime, I click on the textField and the UIDatePicker appears. The function that the selector points to is executed. As soon as I click a UI object outside of the UIDatePicker, the app crashes with this error:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[YourApp.PromiseViewController
dueDateChanged:]: unrecognized selector sent to instance 0x100b12ae0'
What I don't understand is that the "selector" or pointer to the desired function is recognized initially. However, when I trigger another event from another UI Object this exception is thrown.
Why is this happening?
Shouldn't this exception be triggered when datePickerValueChanged() is called initially?
Just add #objc in front of your function
#objc func datePickerValueChanged(_ sender: UIDatePicker){
//Do Stuff
}
The error is telling you that an action with the selector dueDateChanged(_:) has been added as a target action.
More than one target action can be added to a control. Somewhere, maybe in your storyboard or xib, you have another action added to dueDatePicker.

Having trouble targeting a DesignableView in a UITableViewCell upon tapping it in order to change

and thanks in advance for taking the time to help.
Inside my CellForRowAtIndexPath, I have the following line:
cell.timeView.addTarget(self, action: "ButtonDidPress:", forControlEvents: UIControlEvents.TouchUpInside)
and my selector function is:
func ButtonDidPress (sender: DesignableView!){
let view:DesignableView = sender
cell.timeView.shadowColor = UIColor.yellowColor()
table.reloadData()
}
and the error i get is:
unrecognized selector sent to instance
I'm thinking that perhaps one can't send a View as a selector (am I using the correct terminology?), but how else can I target that particular view in that cell?
UPDATE:
I also tried using gestureRecognizer instead:
var tap = UIGestureRecognizer(target: self, action: Selector( "viewDidTap:"))
cell.timeView.addGestureRecognizer(tap)
and
func viewDidTap (sender: DesignableView!){
but I got the same error here.
Thanks!
There's a couple of strange things happening in your code. It seems you want to change the shadowColor property of timeView when a user touch it, right?
Two possible solutions are:
(This one is IMO the better one) Change DesignableView to inherit from UIButton. Then you can set:
timeView.addTarget(self, action: "ButtonDidPress:", forControlEvents: .TouchUpInside). Make sure you set it just once for each cell. Otherwise you will get multiple calls on one tap.
Use UITapGestureRecognizer, but you should put it in your UITableViewCell subclass, not to the view controller. Also, the sender in viewDidTap is not the view itself, but the recognizer. So the method will go like this:
func viewDidTap(sender: UITapGestureRecognizer) {
let location = sender.locationInView(sender.view)
if timeView.hitTest(location, withEvent: nil) == timeView {
timeView.shadowColor = UIColor.yellowColor()
// table.reloadData() - you don't need to reload the table
}
}

Swift iOS: Drag & Drop between two Containers fails

I'm entering the world of Swift, stepping forward slowly...
What I'm trying to have is an UIViewController with two Container Views, each of them having its own UIViewController with an UITableView, where it is possible to drag a table entry from the right container's table, and drop it on the left container's table. The parent UIViewController shall care about everything around that drag'n'drop operation.
I therefore added a Long Press Gesture Recognizer to the UIViewController and wired it accordingly:
#IBAction func longPress(sender: UILongPressGestureRecognizer) {
switch(sender.state) {
case UIGestureRecognizerState.Began: startDragDrop(sender)
case UIGestureRecognizerState.Ended: endDragDrop(sender)
default: return
}
}
where
func startDragDrop(sender: UILongPressGestureRecognizer) {
var startPoint: CGPoint = sender.locationInView(self.structureElementContainer!.tableView)
var indexPath = self.structureElementContainer.tableView.indexPathForRowAtPoint(startPoint)!
println("startPoint: \(startPoint.x) \(startPoint.y)")
println("\(indexPath.section) \(indexPath.row)")
}
When long-clicking on a table entry, there is a crash in the "var startPoint" line:
2015-03-20 15:45:59.822 xxx.20[10274:18100886] -[UIView tableView]: unrecognized selector sent to instance 0x7a14fa90
2015-03-20 15:45:59.828 xxx.20[10274:18100886] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView tableView]: unrecognized selector sent to instance 0x7a14fa90'
What's going wrong here?
Thanks a lot for your support
[Added 23-mar-2015]
I tried now to follow Mundi's hint, but without success up to now.
This is the view controller fragment of the parent, where I added outlets for the two containers:
class xxxDetails: UIViewController {
#IBOutlet weak var viewTitle: UILabel!
#IBOutlet weak var aaaElementsContainer: UIView!
#IBOutlet weak var bbbStructureContainer: UIView!
#IBOutlet var gestureRecognizer: UILongPressGestureRecognizer!
var structureElementsController: StructureElementsController!
override func viewDidLoad() {
super.viewDidLoad()
}
The containers embed a UITableViewController each:
class aaaElementsController: UITableViewController {...}
class bbbElementsController: UITableViewController {...}
I tried to create an Outlet for those controllers in the parent UIViewController, without success.
I tried to create a property in the UITableViewController which refers to itself, to be able to access it from the parent, without success.
It seems that I'm possibly following a wrong approach. So the question is now for me: When embedding two child UITableViewControllers via ContainerViews in a parent UIView, how do I access those children correctly, so that I'm able to have gesture recognition in the parent which is able to follow a drag&drop from the one child to the other?
Your self.structureElementContainer does not have a tableView property. Presumably the controller of that view has one. You have to refactor to have the main view keep a reference to the controllers, not the views.
Well, Mundi's response did not solve my problem directly, but it put me on the track of a sequence of information that led to the solution... ;-)
I was pretty surprised that things may be so simple. I was stuck on the fact that I did not get a valid handle to the subview controllers. However, to get these handles, you just have to care about the embed segue during viewDidLoad:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "aaaElementsSegue" {
aaaElementsController = segue.destinationViewController as AaaElementsController
}
}
After that, the aaaElementsController is valid and allows access to the table view in the child view.
And, as this is true for the second child view, I'm now able to handle the drag&drop between those two child views.

UISegmentedControl unrecognised seletor

I am trying to add a UISegmentedControl to my app, but it seems that i always get [UISegmentedControl longValue]: unrecognised selector sent to instance 0x22f44e00
This is how i declare my UISegmentedControl
#IBOutlet var speedControl: UISegmentedControl
override func viewDidLoad() {
super.viewDidLoad();
self.speedControl.addTarget(self, action: "selectedSegmentDidChange:", forControlEvents: .ValueChanged);
self.speedControl.selectedSegmentIndex = 0;
}
func selectedSegmentDidChange(segmentedControl: UISegmentedControl) {
NSLog("method called");
}
How do i solve this?
I noticed none of my codes i wrote was causing the error, but it was the storyboard itself.
I right-clicked on the UISegmentControl, I noticed there were weird connections made to unknown source. I deleted them by pressing the "X", and everything is fine now

Resources