Need Help Transfer Data From Button

I am not sure how to transfer data a name from a button in my UITableViewCell to a UIViewController. I have a prepare function but it doesn't work gives me an unrecognized selector error. Is there a way to use it for this instance?

func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "hs" {
    let destinationController = segue.destination as! HighlightsVC
      destinationController.playerName = (item.yahooName!)
  }
  }

Replies

gives me an unrecognized selector error

Which line ?

You need to retrieve the item, which is the selected cell.
You can do this in didSelectRow to keep the selectedCell reference. Or you could also extract there item.yahooName and keep it in a var selectedName in VC and use it in prepare.

Another point: don't force downcast. If it fails, app will crash

      let destinationController = segue.destination as! HighlightsVC
      destinationController.playerName = (item.yahooName!)

But conditionnal unwrap:

if  let destinationController = segue.destination as? HighlightsVC {
      destinationController.playerName = selectedName      // Set in didSelectRow
}

No need either for parenthesis around name, but for such code, use ?? operator:

      destinationController.playerName = item.yahooName ?? ""

The thing is I don't want the whole cell to be selected. I just want the button to be.

The thing is I don't want the whole cell to be selected. I just want the button to be.

When you tap the button, de facto you select cell. So probably you can use

optional func tableView(_ tableView: UITableView,  willSelectRowAt indexPath: IndexPath) -> IndexPath?

to get the select and immediately deselect it so that it is not highlighted. But in the meantime, get the cell reference and name.

I am still confused I don't understand what you mean by cell reference. I am also not sure how to reference the VC inside of UITableViewController.

What exactly should I put in my button in my cell that does the action?

   @IBAction func CamButtonA(_ sender: UIButton) {
    //?
    }

what you mean by cell reference

In willSelectRowAt, you can either get the cell itself or you can directly get the yahooName of the cell. And save it in a global var of the VC.

Then, the segue is from the VC (not the cell) to the next VC. In prepare, you set the name as you have done.

In IBAction, just call the segue:

@IBAction func CamButtonA(_ sender: UIButton) {
              performSegue(withIdentifier: "hs", sender: nil)  // No need to know  the sender here
    }

This is the best I could do with making a global variable but what do I put inside exactly willSelectRowAt, You can't put any segues in there.

struct GlobalFavPlayer {
   
  func addObserver() {
  NotificationCenter.default.post(name: .passFavNotification,
                  object: GlobalFavPlayer.globalFav)
  }
   
  static var globalFav: CurrentPlayers?
   
   
}

You can't put any segues in there.

What is the problem ? Do you get an error message ? Did you create the segue between VC (not cell) and the destination ?

I get the error '-[LearnHockey.FavCell CamButtonA:]: unrecognized selector sent to instance 0x7f9fe6038800'. I created the segue too but I don't know what to put in my willrowat exactly.

   override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "hs" {
    let destinationController = segue.destination as? HighlightsVC
      destinationController!.playerName = GlobalFavPlayer.globalFav!.yahooName!
  }
  }

   override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    //not sure what to put in here
  }

What I would do here, which is probably the simplest:

  • declare a var in VC
var selectedNameInCell : String?
  • get it in willSelectRowAt or in didSelectRowAt if you prefer:
   override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    // what is the dataSource ? I assume it is an [Item] ; I assume you have a single section
    selectedNameInCell = dataSource[indexPath.row].yahooName
    return nil    // cancel selection of cell
  }
  • Now you can use in prepare
   override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
      if segue.identifier == "hs"  {
          if let destinationController = segue.destination as? HighlightsVC, let destName = selectedNameInCell {
              destinationController!.playerName = destName
           }
      }
  }

Oh I forgot to mention that my data source is a set so it is not like that. I'm not sure how to get the value from the cell like you have done.

var favSet: Set<CurrentPlayers> {
    FavouriteManager.shared.favSet
  }

It's risky to have dataSource as a Set, because order will change. Don't you mind ?

Anyway, just replace

selectedNameInCell = dataSource[indexPath.row].yahooName

with

   override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
      if let cell = cellForRow(at: IndexPath) {
         selectedNameInCell = cell.yahooName     // I assume you have such a property in the cell ; or maybe it is just cell.textLabel!.text if the name is the textLabel
     }
  }

Okay I will do that. I have a set because I wanted to avoid duplicates with an array.

I wanted to avoid duplicates with an array.

Yes, that's logical, but you should handle it when you populate the array. Or remove any duplicate in the array:

var myArray = [/* Some items*/]
var noReplicateArray = [] // with same types of items

for item in myArray {
    if !noReplicateArray.contains(item) {
        noReplicateArray.append(item)
    }
}

You can also use reduce:

noReplicateArray = myArray.reduce([]) {array, item in if array.contains(item) { return array } else { return array+[item] } }

But the first appears to be much faster.