0

I have an app which utilizes a tableView which contains a prototype cell. This prototype cell contains a few labels and a button (connected to that cell's UITableViewCell file). If that's not clear, this is what I mean:

class ContactsCell: UITableViewCell { //this custom cell is used as the prototype cell for the tableView

    @IBOutlet weak var firstNameLabel: UILabel!

    @IBOutlet weak var lastNameLabel: UILabel!

    @IBOutlet weak var numberLabel: UILabel!

    @IBOutlet weak var indexPathRowLabel: UILabel!

    @IBOutlet weak var replaceContactButtonUI: UIButton!

    @IBAction func replaceContactButtonTapped(_ sender: Any) {
        //THIS is the button in question
    } 

The reason for this is because I'd like each cell in the tableView to have all of those labels (and the button), but with each row having different values in the labels. These values are handled by the cellForRowAt tableView function, via a system as follows:
Pressing a button (not the button in the cells I was talking about... a different button that is at the top of the VC, outside of the tableView) brings up the contact picker:

 func selectContact(){//allows user to bring up contactPicker

        let contactPicker = CNContactPickerViewController()
        contactPicker.displayedPropertyKeys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey, CNContactImageDataKey]

        contactPicker.delegate = self

        contactPicker.predicateForEnablingContact = NSPredicate(format: "phoneNumbers.@count >= 0")

        contactPicker.predicateForSelectionOfContact = NSPredicate(format: "phoneNumbers.@count >= 1")

        self.present(contactPicker, animated: true, completion: nil)
    }
    @IBAction func selectContactsButton(_ sender: Any) {
        selectContact()
        //button brings up the picker to allow selection of contact
    }

Selecting one of the contacts updates an array which is used by the tableView to update the value of the labels:

func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
    contactArray.append(contactProperty.contact)
    print(contactArray)// contactArray = [CNContact]()
    contactsTableView.reloadData()// reloads the value of the labels
    dismiss(animated: true)
}

These all work as intended. However, I run into a bit of an issue with the button that is in each cell. This button is intended to allow the replacement of a the CNContact in the tableView at the row of which the button was pressed... (ie if there are 4 rows, there are 4 "replace" buttons. Clicking the "replace" button of the third row replaces the CNContact at the 2nd index of the contactArray). This is where my issue is, though. Since the button, and its action, lives in the UITableViewCell's swift file, and not in the tableViewControllers, it doesn't have access to the contactArray to remove and append, nor the picker functions to allow the selection of the new contact, nor the tableView itself to run .reloadData(). How do I 'give access' to the UITableViewCell's swift file to utilize things from the tableView controller that it is a part of/connected to?
Note Its possible that the entire premise of this question is wrong and that I should've actually placed the button's action elsewhere (not in the UITableViewCell's swift file). If this is the case, where should I put it?

2 Answers 2

1

Since you have all the information in your ViewController, I would suggest moving your @IBAction into your ViewController as well. If you are worried about referencing the correct cell, you can set the tag value of your UIButton in cellForRow method. Then in @IBAction, you can use that value to access the correct index in the array as well as the cell itself

Sign up to request clarification or add additional context in comments.

10 Comments

But how do I connect the @IBAction of the button if all of the cell components are located in the UITableViewCell?
You can connect it in the storyboard just like any other button. Ctrl+click the button and drag it to the yellow circle at the top (UIViewController)
So I can use a prototype cell (with all the custom placement of UI elements) without putting their references in the UITableViewCell files? Sorry if that's a stupid question, but that's just the way I have always done it and haven't ever even thought to do it otherwise.
It is a good practice to have a separate file for Custom cells and referencing your @IBOutlets there. But when it comes to @IBActions, I tend to use them in the ViewControllers where they will be used and then just hook them up from storyboard. To put it another way, you can link an @IBAction of a UIButton (in a custom cell with an @IBOutlet linked to the CustomCell file) to an @IBAction method written in your ViewController
How do I do that? How do I link the IBAction from the CustomCell file to the IBAction in the VC? That would basically answer the question
|
1

you can give selector to button in cellforrowatindexpath:

 cell.replaceContactButtonUI.tag = index.row
  cell.replaceContactButtonUI.addTarget(self, action: #selector(self. 
selectContact(sender:)), for: .touchUpInside)

  func selectContact(sender:UIButton){}

From button tag you can find the cell index by sender.tag.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.