Using UITextView in a tableViewCell

Here is the set up:


a custom cell, with a single item in the content view : a UITextView.

class CustomeCell: UITableViewCell
    @IBOutlet weak var aTextView: UITextView!

with its nib


It displays well, I can type text inside.


But I cannot find a way to get in a var the text that was typed


Here is what I try :


var toGetText: String
guard let aCell = aCell as? CustomeCell else {  return   }
toGetText = aCell.aTextView.text ?? ""     // I get there, but text is empty or nil

toGetText remains empty (does not get what was typed in)


I tried to print several variations:

print(aCell.aTextView.text, "Attributed",  aCell.aTextView.attributedText, "Storage: ",  aCell.aTextView.textStorage.string,"Storage attributed: ",  (aCell.aTextView.textStorage as NSAttributedString).string)

just get empty content

Optional("") Attributed Optional() Storage: Storage attributed:


So I am misusing UITextView, but cannot find the correct use.

Answered by OOPer in 327399022

That makes me think that the cell reference is correct.


I really doubt that. As seeing this line:

let aCell = tableView(actionsTableView, cellForRowAt: indexPath)

You usually do not call `tableView(_:cellForRowAt:)` directly. It's for the iOS system to get a populated cell which is getting visible from now on.

You may get the right cell (it's reused) incidentally, but I believe you should not rely on such a luck.


This is not the recommended way, but change the line as below and see what you get.

let aCell = actionsTableView.cellForRow(at: indexPath)


Generally, you should better not consider view objects as storage. When you have editable fields in your cell, you should reflect the content to your model object immediately.


EDITED


You have no need to touch textStorage of a UITextView, unless you want to control the editing behavior yourself. Just use the property `text` or `attributedText`.

One possibility, your `aCell` may not be the same cell in which you entered some text. How do you get it? Please show more code.

I have a global var for testing

   var fullRecommendation: String = "Already some text\n"


the cell class:


class RecommendationCell: UITableViewCell {

    @IBOutlet weak var recommendationTextView: UITextView!
 
    override func awakeFromNib() {
     
        super.awakeFromNib()
        // Initialization code
        // Display the partial existing recommendation if exist
        let attributedText = NSAttributedString(string: fullRecommendation, attributes: [:])  
        recommendationTextView.textStorage.setAttributedString(attributedText)
    }

}


When cell is loaded, it displays

Already some text


I can then enter more text in the textView, even modify the existing one. But modifications only appear on screen, I cannot read them in the following IB Action:


Here, I have different types of cell prototypes.

All the cases are handled properly: aCell.valueOrText.text does get what was typed in the textField.

That makes me think that the cell reference is correct.


So the problem seems really due to my using UITextView ; just as if when entering text, I was working on a copy of a container. Should I declare dome storage as Mutable for UITextView ? (I had to do something like this on an OSX app)



    @IBAction func validate(_ sender: UIButton) {
      
                    let indexPath = IndexPath(row: iCell, section: 0)
                    let aCell = tableView(actionsTableView, cellForRowAt: indexPath)

                    switch sectionNum!.typesOfCells[iCell] {

                   case .inputText:
                        guard let aCell = aCell as? InputDataCell else {
                            return
                        }
                        Global.shared.fullReport[numSection][aCell.tag].typedText = aCell.valueOrText.text ?? ""

                    case .comments:  //  cell with UITextView
                        guard let aCell = aCell as? RecommendationCell else {
                            return
                        }
                        print("Recomms", aCell.recommendationTextView.text)
                        Global.shared.fullRecommendation = aCell.recommendationTextView.text ?? ""
                        Global.shared.fullReport[numSection][aCell.tag].typedText = Global.shared.fullRecommendation
                     }
                }
            }
        }
    }



EDITED


Seems I need to use textStorage.

If I add on line 18

                        let attributedText = NSAttributedString(string: "Added some text\n", attributes: [:])
                        aCell.recommendationTextView.textStorage.append(attributedText)

then I get the text added to the UITextView.


So the question is : how to get the text that is displayed on screen in the UITextView.

Then I could just call

     let attributedText = NSAttributedString(string: theTextOnScreen, attributes: [:])
     aCell.recommendationTextView.textStorage.setAttributedString(attributedText)
Accepted Answer

That makes me think that the cell reference is correct.


I really doubt that. As seeing this line:

let aCell = tableView(actionsTableView, cellForRowAt: indexPath)

You usually do not call `tableView(_:cellForRowAt:)` directly. It's for the iOS system to get a populated cell which is getting visible from now on.

You may get the right cell (it's reused) incidentally, but I believe you should not rely on such a luck.


This is not the recommended way, but change the line as below and see what you get.

let aCell = actionsTableView.cellForRow(at: indexPath)


Generally, you should better not consider view objects as storage. When you have editable fields in your cell, you should reflect the content to your model object immediately.


EDITED


You have no need to touch textStorage of a UITextView, unless you want to control the editing behavior yourself. Just use the property `text` or `attributedText`.

You're right.


And I'm a bit furious against myself, because I once had this problem and realized that cell is not a storage.


Anyway, thanks a lot.

Using UITextView in a tableViewCell
 
 
Q