-1

Original post:

As suggested from the title. I have made sure that when the cell is initiated in the cellForRowAt method, the cell's textview will be assigned a delegate from within the method. In fact, there is another text field in the cell, and it works fine for text field, that the textfield delegate methods are called as expected. However, when it comes to the textview, I have done the same thing, but the delegate seems to become nil after the cell initialisation, and textview delegate methods are not called as expected.

I have tried with playground: set up a view controller that contains a textview, assigning a delegate to it, and added a print message to the textViewDidBeginEditing method, and the message is printed out as expected when I tap the textview. I am really not sure what causes this problem.

The only thing that I am sure is that, in the cellForRowAt tableview datasource method, the delegate is still existent. I have no idea what happens afterwards. Any thoughts?

FYI: category is the textfield, detail is the textview.

for cellForRowAt method

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    //the rest of the added cells for other categories
    let cellForOtherCategories = tableView.dequeueReusableCell(withIdentifier: addListTableViewCellID, for: indexPath) as! AddListTableViewCell
    cellForOtherCategories.addListTableViewCellDelegate = self

    cellForOtherCategories.category.delegate = self

    print("Before delegate is set")

    cellForOtherCategories.detail.delegate = self

    print("After delegate is set.")

    print(cellForOtherCategories.detail.delegate.debugDescription)


    return cellForOtherCategories
}

for text view delegate:

func textViewDidBeginEditing(_ textView: UITextView) {
    print("This should go first")
}

Update 1:

The text view delegate method is called only when tapping the text view for the second time. But this is still very weird, that why aren't the delegate methods called when text view is tapped for the first time onward.

To illustrate the situation, let's say there is a text view, assigned a delegate, implemented textViewDidBeginEditing containing a print message. When I first tapped the text view, the message was not printed. However, after I resigned the text view as the first responder (tapped somewhere else) and tapped the text view again, the delegate method was called.

Update 2:

Since textViewShouldBeginEditing is called before textViewDidBeginEditing, I tried to put the print message in the textViewShouldBeginEditing to test if this delegate method works. And it turns out to be working. So Now the problem is drilled further down to, why is textViewDidBeginEditing not called for the first time, while the other method is called?

Update 3:

After I assigned the cell's delegate to be itself, and adjusted my programme accordingly, the same problem appeared again. Since the test in the playground works, I think the problem is actually not about the assignment of delegate. Something else has caused the problem. When I think about if there is any difference between my programme and the test code, it is the observer. (Or probably something else? But I cannot figure out since the others are mainly various views, which should not have any influence on invoking the textview delegate methods.)

I have one observer, whose notification is UIResponder.keyboardWillHideNotification, so the method of the observer will be, and should be, called only after I tapped the textview and subsequently invoking the textview delegate methods.

Is there any behind-the-scene happening for the UITextView when it comes to observer, such that the textview delegate method textViewDidBeginEditing is not called on the first tap? Since there is no problem with textfield.

qsmy
  • 383
  • 3
  • 14
  • can you please post the code of the initialisation of the cell, where you assign the delegates and so on. Also the cellForRow and the methods not being called. – jastrada Jun 12 '19 at 16:16
  • @jastrada Hi, I added the methods. – qsmy Jun 12 '19 at 16:23
  • Are you saying that `print(cellForOtherCategories.detail.delegate.debugDescription)` prints `nil`? – rmaddy Jun 12 '19 at 16:57
  • @rmaddy No what I am saying is that `print(cellForOtherCategories.detail.delegate.debugDescription)` prints an optional with a value. This shows that the delegate is assigned. but when I went on to try to `print("This should go first")`, it fails, i.e. nothing was printed. – qsmy Jun 12 '19 at 17:13
  • Where did you put the `textViewDidBeginEditing` function? Make sure it's not inside another function. It needs to be at the top level of the view controller class or extension. – rmaddy Jun 12 '19 at 17:22
  • I confirm that it is placed in the extension of the view controller which conforms to the `UITextViewDelegate`. – qsmy Jun 12 '19 at 17:24

1 Answers1

1

This is messy since the ViewController that has the tableView will be delegate of multiple textViews and textFields. I would suggest to create a setup function inside AddListTableViewCell.

There you would setup the delegates, which should be each cell.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cellForOtherCategories = tableView.dequeueReusableCell(withIdentifier: addListTableViewCellID, for: indexPath) as! AddListTableViewCell

    cellForOtherCategories.setupCell()

    return cellForOtherCategories
}

Then, on AddListTableViewCell you will have the method:

func setupCell() {
    self.categoryTextField.delegate = self

    self.categoryTextView.delegate = self

    //And whatever you need..
}

Finally add the extension to the cell to be able to assign it.

extension AddListTableViewCell: UITextViewDelegate {

    func textViewDidBeginEditing(_ textView: UITextView) {
        print("There you go")
    }

}
jastrada
  • 384
  • 1
  • 8
  • I tried to use the cell itself as its delegate, and it worked fine, but what I want is to "centralise" the delegates to be the view controller so that I can handle all the textview and textfield delegate methods in one single view controller. That's why I tried to assign the text view's delegate as the view controller itself. If this centralised idea really doesn't work, and the textview delegate cannot be assigned to the view controller, I think I will change back to cell itself. – qsmy Jun 12 '19 at 17:10
  • It's not a good practice in terms of design and clean code, also I suspect there are a few issues since it's a delegate of multiple cells of the same type. Instead, when you assign it as delegate of the tableView, it's just one. – jastrada Jun 12 '19 at 17:50
  • The other reason why I wanted to do so is that those view's delegate methods actually call almost the same function, and I find it rather repetitive to have every single subview implementing delegate methods. Thus I would like to write them only once by gathering them all in the view controller. This works for textfield, and I actually have two textfields' delegate assigned to the view controller, and both of them work fine. But when it comes to textview, the delegate cannot be successfully assigned... How strange.. – qsmy Jun 12 '19 at 18:02