0

I have two UILabels with two UITapGestureRecognizers in a UITableViewCell.

cell.Username.tag = indexPath.row
cell.SharedUser.tag = indexPath.row
let tapGestureRecognizer2 = UITapGestureRecognizer(target:self, action:"GoToProfil:")
let tapGestureRecognizer3 = UITapGestureRecognizer(target:self, action:"GoToProfil:")
cell.Username.userInteractionEnabled = true
cell.Username.addGestureRecognizer(tapGestureRecognizer2)
cell.SharedUser.userInteractionEnabled = true
cell.SharedUser.addGestureRecognizer(tapGestureRecognizer3)

func GoToProfil (sender: AnyObject!) {
    self.performSegueWithIdentifier("GoToProfilSegue", sender: sender)
}

I'm using a Segue to push another UIViewController, and I'm overriding the PrepareSegue function to send the needed information corresponding to the Sender tag.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {

    let ProfilView = segue.destinationViewController as! Profil
    ProfilView.hidesBottomBarWhenPushed = true
    ProfilView.title = posts[sender.view!.tag].User?.objectForKey("Name") as? String
    ProfilView.User = posts[sender.view!.tag].User
}

My problem is that I want to know which UILabel was pressed, knowing that I'm already using tag.

Brian
  • 14,610
  • 7
  • 35
  • 43
Stranger B.
  • 9,004
  • 21
  • 71
  • 108
  • What's a `UITextLabel`? There's no such thing. – rmaddy Feb 08 '16 at 22:18
  • Sorry I edited the post, I meant UILabel – Stranger B. Feb 08 '16 at 22:19
  • You could add a different function to be called when the second UILabel is tapped. Then that function would call for a different seg identifier, such as, `performSegeueWithIdentifier("GoToProfilSeg2")` . Then in your `prepareForSegue` method you just use an `if` statement to handle which segue is to be perfored, ie `if segue.identifier == "..."" { ... }` – MikeG Feb 08 '16 at 22:25
  • It's useless to have another segue showing the same View Controller – Stranger B. Feb 08 '16 at 22:28
  • 2
    FYI - it is standard naming conventions that function and variable names begin with lowercase letters and only class names begin with uppercase letters. – rmaddy Feb 08 '16 at 22:31
  • @YasserB. What do you need to do differently depending on whether the `Username` or `SharedUser` label was tapped? – rmaddy Feb 08 '16 at 22:47
  • You said you are using tags, why not just use the tag to determine whom the sender is? The whole point of tags is to uniquely identify the view in a hierarchy. – CStreel Feb 08 '16 at 22:57
  • You can use something like an even or pair tag to differentiate. (indexPath.row*2) and ((indexPath.row*2)+1) – Ulysses Feb 08 '16 at 22:57
  • @YasserB. are you using the tag to track row or are you trying to uniquely identify the two labels so you can easily tell them apart? – CStreel Feb 08 '16 at 23:04
  • @CStreel I'm already using the tag to identify the cell and I want to identify which label was taped in the same time. – Stranger B. Feb 08 '16 at 23:07
  • @YasserB. My updated answer solves that now. BTW - never use the tag to identify the row. It fails miserably if your table allows rows to be inserted, deleted, or reordered. – rmaddy Feb 08 '16 at 23:08
  • @YasserB. I've submitted a possible solution, I hope it helps with what you are trying to achieve. – CStreel Feb 08 '16 at 23:14
  • I also update the answer, check if the even/odd solution will help you. – Ulysses Feb 08 '16 at 23:18

4 Answers4

5

Your GoToProfile: function should be written properly. The parameter isn't the "sender", it's the gesture recognizer.

func GoToProfil (gestureRecognizer: UITapGestureRecognizer) {
}

From there, you can determine the label by using the view property of the gesture recognizer.

But you seem to have two conflicting requirements. You want to know which of the two labels was tapped and you want to know which row the label is in.

Normally you would use the label's tag to know which of the two labels was tapped. But you are using their tags to track the row.

The solution I recommend is to use the tag to differentiate the two labels. Then you can calculate the row based on the frame of the label.

See the following answer for sample code that translates the frame of a cell's subview to the cell's indexPath.

Community
  • 1
  • 1
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • Can you please show how to determine the label using the view property, this what I'm missing – Stranger B. Feb 08 '16 at 22:27
  • I don't know Swift but something like `let label = gestureRecognizer.view as UILabel`. I'm sure that's not 100% correct but that should help. – rmaddy Feb 08 '16 at 22:28
  • depends what you tagged @YasserB. if you tagged the inner subview and the container got passed it will not work since the view your examine is not the one you tagged and using viewTags this way is very very fragile – David Yang Liu Feb 08 '16 at 22:40
  • @YasserB. Clarify what you mean by "doesn't seem to work". – rmaddy Feb 08 '16 at 22:41
  • 1
    I think @YasserB wants to be able to identify whether is was the `Username` or the `SharedUser` label which was tapped. Just having the label doesn't tell them which of the two it is, and the tag has already been used for another purpose so it can't be used. – vacawama Feb 08 '16 at 22:43
  • @vacawama Yeah, you're right. I misread what the issue was after getting caught up with the incorrect action method. – rmaddy Feb 08 '16 at 22:46
  • @vacawama I updated the answer to deal with the issue. – rmaddy Feb 08 '16 at 22:56
  • @vacawama Yeah that's what I want is to be able to identify whether it was the Username or the SharedUser label which was tapped – Stranger B. Feb 08 '16 at 23:06
  • @rmaddy but how can I calculate the row based on the frame of the label, can you give a code example. – Stranger B. Feb 08 '16 at 23:11
  • 1
    @YasserB. I add a link to the end of my answer showing such code. – rmaddy Feb 08 '16 at 23:16
  • @rmaddy Awesome ! this is the solution I was looking for :) – Stranger B. Feb 09 '16 at 12:08
1

Making the following assumptions:

  1. You are trying to uniquely identify the label using UIView.tag
  2. You want different behaviour for Username & SharedUser

I recommend the following, first define your tags below your #imports

#define kUsername 1
#define kSharedUser 2

Then assign them to your views

cell.Username.tag = kUsername
cell.SharedUser.tag = kSharedUser

Then in your prepareSegue

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    int tag = [sender.view!.tag]
    if (tag == kUsername) {
       //Username logic
    } else if(tag == kSharedUser)  {
       //Shared User Logic
    }
}

This way you can easily and simply determine tap, Note this might have different results if you have more then 1 Username & SharedUser labels. Then you will either need more #defines or change how you generate your tags.

CStreel
  • 2,642
  • 2
  • 19
  • 37
1

You can add a property to UILabel to track the label's type. (I used an enum since there's just 2 cases, but it could be a string, etc.)

enum LabelDest : String
{
    case Username = "Username"
     case SharedUser = "SharedUser"
}

extension UILabel
{
    struct Static {
        static var key = "labelDest"
    }
    var labelDest:LabelDest? {
        set { objc_setAssociatedObject( self, &Static.key, newValue?.rawValue, .OBJC_ASSOCIATION_COPY_NONATOMIC )
        }
        get {
            guard let val = objc_getAssociatedObject( self, &Static.key ) as? String else { return nil }
            return LabelDest( rawValue:val )
        }
    }
}

Now you can just do this:

let label = UILabel()
label.labelDest = .Username

Later:

switch label.labelDest
{
    case .Some(.Username):
        // handle user name
        break
    ...

If you want to use the .tag field on your labels you can use a different technique to find the table row associated with a label: (again using class extensions)

extension UIView
{
    var enclosingTableViewCell:UITableViewCell? {
        return superview?.enclosingTableViewCell
    }
    var enclosingTableView:UITableView? {
        return superview?.enclosingTableView
    }
}

extension UITableViewCell
{
    var enclosingTableViewCell:UITableViewCell? {
        return self
    }
}

extension UITableView
{
    var enclosingTableView:UITableView? {
        return self
    }
}

extension UIView {
    var tableRow:Int? {
        guard let cell = self.enclosingTableViewCell else { return nil }
        return self.enclosingTableView?.indexPathForCell( cell )?.row
    }
}

Now, from your gesture recognizer action:

func goToProfil( sender:UIGestureRecognizer! )
{
    guard let tappedRow = sender.view?.tableRow else { return }
    // handle tap here...
}
nielsbot
  • 15,922
  • 4
  • 48
  • 73
  • You can also set this property in IB using the additional runtime properties panel (I think that's what it's called) – nielsbot Feb 08 '16 at 23:45
0

You can access the sender data, and read the tag of the object that send you, like in this sample code.

To uniquely identify each row and each label, you can use something like this:

  • cell.Username.tag = (indexPath.row*2)
  • cell.SharedUser.tag = (indexPath.row*2)+1

With this, if you have a even tag, its the Username, odd will be the SharedUser. Dividing by the floor of 2 you can have the row back.

@IBOutlet weak var test1: UILabel!
@IBOutlet weak var test2: UILabel!



override func viewWillAppear(animated: Bool) {
    test1.tag = 1
    test2.tag = 2

    test1.userInteractionEnabled = true
    test2.userInteractionEnabled = true

    self.test1.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "handleSingleTap:"))
    self.test2.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "handleSingleTap:"))
}

func handleSingleTap(sender: UITapGestureRecognizer) {
    print(sender.view?.tag)
}
Ulysses
  • 2,281
  • 1
  • 16
  • 24