11

I am trying to add labels in Swift, which are added in a loop. I then want to add a 'TapGesture' event to each one as they are added. It works , but the problem is that the function called takes data from the label to use when it's clicked, but the label has been redefined by then and it takes data from the last one added, not the one that was clicked. How can I make each one unique?

self.label.attributedText = self.myMutableString
let tapGesture = UITapGestureRecognizer(target: self, action: handleTap(label))
self.label.userInteractionEnabled=true
self.label.addGestureRecognizer(tapGesture)
self.label.font = UIFont.boldSystemFontOfSize(28)
self.label.sizeToFit()
self.label.center = CGPoint(x: screenWidth, y: top)
if(kilom>=30||self.located==false){
    self.scroller.addSubview(self.label)
    if(device=="iPhone"||device=="iPhone Simulator"){
        top = top+80
    }
    else{
        top = top+140
    }
}

The code below is the gesture recognizer that gets the label data and uses it:

func handleTap(sender:UILabel){
    var a = self.label.text
    let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)

    let resultViewController = storyBoard.instantiateViewControllerWithIdentifier("displayer") 

    self.presentViewController(resultViewController, animated: true, completion: nil)
}
vacawama
  • 150,663
  • 30
  • 266
  • 294
gareth power
  • 209
  • 2
  • 4
  • 12
  • From the code you posted, it seems that you only have one label. You change its attributes but you don't create a new one (unless it's in code that you didn't include). – Phillip Mills Jun 04 '16 at 14:05

2 Answers2

17

The handler function for a UITapGestureRecognizer is passed the UITapGestureRecognizer as the sender. You can access the view that it is attached to with the view property. I would suggest something like this:

func handleTap(sender: UITapGestureRecognizer) {
    guard let a = (sender.view as? UILabel)?.text else { return }

    ...
}

You will also need to change the signature of your selector:

let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))

or for earlier versions of Swift:

let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
vacawama
  • 150,663
  • 30
  • 266
  • 294
  • I am now having the trouble of adding a value for an undefinedkey for each label? I am trying to store data in that but keep getting an error saying "UncaughtNSException" and " this is not a key coding complaint" – gareth power Jun 04 '16 at 15:18
  • What are you trying to do? Update the text of the label? Can you show the line of code giving you the error? – vacawama Jun 04 '16 at 15:22
  • No, when the label is clicked, I want the handletap function to get data from the label, (which I want to store when it is created): self.label.setValue(data[0], forUndefinedKey: "name") The error is: NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key timelineTable – gareth power Jun 04 '16 at 15:35
  • A label is a UI element. You really shouldn't be trying to store data there. If you want to associate data with a label, you could assign a tag value (which is an Int) to the label and then use that tag to access data in an array of structs or a dictionary. – vacawama Jun 04 '16 at 15:40
  • Well, I'm only trying to store the data in the label for when it is later needed to be saved (when the label is clicked). but how do I assign a tag value then? – gareth power Jun 04 '16 at 15:44
  • `label.tag = 15`. Just give each label a unique tag when you create it, and store the value you are trying to save/retrieve in a dictionary that is a property of your viewController. `myDict[tag] = "valueToRetrieveLater"`. In handleTap: `guard let tag = sender.view?.tag else { return }` and `if let valueToSave = myDict[tag] { // save the value }`. – vacawama Jun 04 '16 at 15:49
  • Okay, I understand most of it and have no errors. but what is myDict? i.e. How do i define it? – gareth power Jun 04 '16 at 15:55
  • Just put `var myDict = [Int: String]()` as a property of your viewController. That assumes you're storing a `String`. Change it to whatever type of data you are storing. – vacawama Jun 04 '16 at 15:56
  • You're welcome. I also answered your line question from yesterday. – vacawama Jun 04 '16 at 16:15
  • I like this approach, but this doesn't work (as far as I can see) when the labels are part of a `UITableViewCell`; once a cell is reused, the saved tag no longer be associated with the label, correct? – koen Feb 19 '17 at 20:42
5

SWIFT 5.1

Great answer by @vacawana but I just want to post what a complete code will look like to help a bit. You need to add a isUserInteractionEnabled to the label.. as well as the tapGesture created.

let label = UILabel()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))

label.isUserInteractionEnabled = true
label.addGestureRecognizer(tapGesture)
return label

Don't forget to add @objc before "func handleTap"

Perry Kankam
  • 51
  • 1
  • 3