unrecognized selector sent to instance - swift

I suppose this question could be easily classed as a duplicate but can't find answer after searching.
inside cellForRowAt for my tableView
let chooseProfilePhotoPicker = ChooseProfilePhotoPicker(rootVC: self)
chooseProfilePhotoPicker.cropVC.delegate = self
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(chooseProfilePhotoPicker.iconImageViewTapped(_:)))
cell.iconImageView.addGestureRecognizer(tapGesture)
And the ChooseProfilePhotoPicker class:
class ChooseProfilePhotoPicker: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var rootController: UIViewController
init(rootController: UIViewController) {
self.rootController = rootController
}
func iconImageViewTapped(_ recognizer: UITapGestureRecognizer) {
var pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.photoLibrary
rootController.present(myPickerController!, animated: true, completion: nil)
}
}
app crashes when I tap the iconImageView

If the action is supposed to run in in the instance of ChooseProfilePhotoPicker you have to set the target accordingly:
let tapGesture = UITapGestureRecognizer(target: chooseProfilePhotoPicker, action: #selector(chooseProfilePhotoPicker.iconImageViewTapped(_:)))

Related

UITapGestureRecognizer not attaching action

I created a separate class for View.
I left all the functions in the Controller.
But when I add a click on the picture, it doesn't work for some reason.
import UIKit
class APOTDView: UIView {
var imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(APOTDViewController.imageTapped(_:)))
imageView.addGestureRecognizer(tap)
return imageView
}()
}
import UIKit
class APOTDViewController: UIViewController {
let av = APOTDView()
override func viewDidLoad() {
super.viewDidLoad()
// ... add subview and constraint
}
#objc func imageTapped(_ sender: UITapGestureRecognizer) {
print("good job")
}
}
What's the matter? Please help me figure it out
Your selector in the UITapGestureRecognizer is wrong. You can not call the APOTDViewController directly.
APOTDViewController.imageTapped would be a static function, which is not available.
You can use a delegate instead.
Delegate Protocol and View.
protocol APOTDViewDelegate: AnyObject {
func viewDidTapImage()
}
class APOTDView: UIView {
weak var delegate: APOTDViewDelegate?
var imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
imageView.addGestureRecognizer(tap)
return imageView
}()
#objc func imageTapped() {
delegate?.viewDidTapImage()
}
}
ViewController:
class APOTDViewController: UIViewController, APOTDViewDelegate {
let av = APOTDView()
override func viewDidLoad() {
super.viewDidLoad()
av.delegate = self
// ... add subview and constraint
}
#objc func viewDidTapImage() {
print("good job")
}
}
This will not work, because you are calling the UIViewController method directly without any class reference or object. The solution is to use protocol or clouser to get action from view to class.
class
class APOTDView: UIView {
#objc var imageViewAction: ((UITapGestureRecognizer) -> Void)? = nil
lazy var imageView: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = .blue
imageView.translatesAutoresizingMaskIntoConstraints = true
imageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector((imageTapped(_:))))
imageView.addGestureRecognizer(tap)
return imageView
}()
#objc private func imageTapped(_ sender: UITapGestureRecognizer) {
self.imageViewAction?(sender)
}
}
ViewController
class APOTDViewController: UIViewController {
let av = APOTDView()
override func viewDidLoad() {
super.viewDidLoad()
av.imageViewAction = { sender in
print("good job")
}
}
}

can not call selector and gesture delegate iOS 13.2

my code works in iOS 12 last version but after iOS 13 this code can't call the selector
I used UIGestureRecognizerDelegate for iOS 13
here is my code
let panGest = UIPanGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
panGest.delegate = self
txtVw.addGestureRecognizer(panGest)
here is my let txtVw = subVws as! UITextView , txtVw = subVws as! UITextView
I used this code:
let panGest = UIPanGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
self.view.addGestureRecognizer(panGest)
its work but I have one subview and for subview isn't work & call !!
isn't call self.handleTap or gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)
Is this what you want?
class ViewController: UIViewController, UIGestureRecognizerDelegate {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
gestureRecognizer.delegate = self
textView.addGestureRecognizer(gestureRecognizer)
textView.isUserInteractionEnabled = true
textView.isMultipleTouchEnabled = true
}
#objc func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
let translation = gestureRecognizer.translation(in: self.view)
//make sure the view is not nil
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
gestureRecognizer.setTranslation(CGPoint.zero, in: self.view)
}
}
}

Views not performing segue

I have a collection of views and I want to make that when they are tapped, it will perform the same segue. and no view performs any segue.
class ViewController: UIViewController {
#IBOutlet var categoryViews: [UIView]!
let tapGesture = UIGestureRecognizer(target: self, action: #selector(ViewController.move(tap:)))
override func viewDidLoad() {
super.viewDidLoad()
for category in (0..<categoryViews.count) {
categoryViews[category].addGestureRecognizer(tapGesture)
categoryViews[category].isUserInteractionEnabled = true
}
// Do any additional setup after loading the view.
}
#objc func move(tap: UIGestureRecognizer) {
performSegue(withIdentifier: "Animals", sender: nil)
}
}
A single instance of UITapGestureRecognizer can be added to a single view.
In your code, since you're using a single instance of UITapGestureRecognizer for each view, the tapGesture will be added only to the last view in categoryViews array.
You need to create different UITapGestureRecognizer instance for each view in categoryViews, i.e.
class ViewController: UIViewController {
#IBOutlet var categoryViews: [UIView]!
override func viewDidLoad() {
super.viewDidLoad()
categoryViews.forEach {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(move(tap:)))
$0.addGestureRecognizer(tapGesture)
$0.isUserInteractionEnabled = true
}
}
#objc func move(tap: UITapGestureRecognizer) {
performSegue(withIdentifier: "Animals", sender: nil)
}
}
The problem is that this code doesn't do what you think it does:
class ViewController: UIViewController {
let tapGesture = UIGestureRecognizer(target: self, action: #selector(ViewController.move(tap:)))
Your let tapGesture is an instance property declaration, and what follows the equal sign is its initializer. But you can't speak of self in an instance property initializer; there is no instance yet. So self here is taken to be the class. Thus, your tap gesture recognizer "works", but the move message is not sent to your ViewController instance; in effect, it is sent into empty space.
To fix this, you can initialize tapGesture at a time when self does exist. For example:
class ViewController: UIViewController {
let tapGesture : UIGestureRecognizer!
func viewDidLoad() {
self.tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.move(tap:)))

How to show another View controller when a label is clicked

Juts like clicking a button to show another view contoller, is there a way to do that with a label?
Call below function
NOTE: Please set identifier same which you are you in below code
class firstViewController: UIViewController {
#IBOutlet weak var yourlabel: UILabel
override func viewDidLoad() {
super.viewDidLoad()
self.addGesture()
}
func addGesture() {
let tap = UITapGestureRecognizer(target: self, action: #selector(self. labelTapped(_:)))
tap.numberOfTapsRequired = 1
self.yourlabel.isUserInteractionEnabled = true
self.yourlabel.addGestureRecognizer(tap)
}
#objc
func labelTapped(_ tap: UITapGestureRecognizer) {
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let SecondVC = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.navigationController?.pushViewController(SecondVC, animated: animated)
}
}
Second ViewController
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}

swift UITapGestureRecognizer not working on view

I had to create a new thread bcoz it's driving me crazy and all the other answers online are exactly the same. I have done this countless of times but I cannot see what I am missing for the life of me. I am using a "test" view controller just to get the tap gesture working but it isn't working at all... I am fairly certain that I am setting this up correctly, as this is how I've always implemented it in the past: (yes, I have checked the box for isUserInteractionEnabled). I am even implementing this on a different viewcontroller this exact way and it is working...
class TestViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.addGestureRecognizer(tap)
}
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))
#objc func wasTapped() {
print("tapped")
}
}
I have also tried adding the parameters to wasTapped:
#objc func wasTapped(gestureRecognizer: UITapGestureRecognizer) {
print("tapped")
}
You are saying:
override func viewDidLoad() {
super.viewDidLoad()
view.addGestureRecognizer(tap)
}
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))
The problem is the last line:
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))
You cannot just say let tap like that in the middle of nowhere. You are implicitly making an instance property. But you cannot initialize an instance property with a target of self, because self does not exist at the time an instance property is initialized. (I regard the fact that that code even compiles as a bug, and have reported it as such.)
Move that line to the start of viewDidLoad, like this:
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))
view.addGestureRecognizer(tap)
}
Try something like this
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped(sender:)))
tap.numberOfTapsRequired = 1 // Default value
view.isUserInteractionEnabled = true
view.addGestureRecognizer(tap)
}
#objc func wasTapped(sender: UITapGestureRecognizer) {
print("tapped")
}
You have to enable interaction if you want to use gesture recognizers for standard UIView's
Add view.isUserInteractionEnabled = true in your viewDidLoad.
var tapGesture = UITapGestureRecognizer()
take a view and set IBOutlet like:
#IBOutlet weak var viewTap: UIView!
Write pretty code on viewDidLoad() like:
tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.myviewTapped(_:)))
tapGesture.numberOfTapsRequired = 1
tapGesture.numberOfTouchesRequired = 1
viewTap.addGestureRecognizer(tapGesture)
viewTap.isUserInteractionEnabled = true
this method is calling when tap gesture recognized:
#objc func myviewTapped(_ sender: UITapGestureRecognizer) {
if self.viewTap.backgroundColor == UIColor.yellow {
self.viewTap.backgroundColor = UIColor.green
}else{
self.viewTap.backgroundColor = UIColor.yellow
}
}