title: Read More and Read Less in UITextView : Ilya Puchka readMoreTextView not working
body: <p>I have tested Ilya Puchka's <code>readMoreTextView</code> pod and on static text inside the project it works. but I am trying it with text that comes from a back end api. </p>
  
  <p><strong>Issue</strong> : the cell will not expand fully to reveal all the text. It will reveal about half of the height of the next line...meaning, if the text is 14 pix high, then the READ MORE option will only display only the top half of the text..</p>
  
  <p>If I disable <code>readmoretext</code> options, and use the <code>textView</code> as a plain <code>textView</code>, then <code>textview</code> will display the entire text,... until I scroll.</p>
  
  <p>when I scroll, I lose about 12 lines of text in one messages.</p>
  
  <p>Is a <code>textView</code> just bad for lone singe strings rom a backend? </p>
  
  <p>so this tells me its a <code>tableView.reloadData()</code> or a <code>GCD</code> issue. But I am lost, I don't know where to try. test either option.</p>
  
  <p>I am mixing two pods, <code>AzureBot</code> and <code>ReadMoreTextView</code>. the string / text comes from the azure bot and then gets loaded into the textview. </p>
  
  <p>I now realize I suck at such a simple task. </p>
  
  <pre><code>override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
          let message = self.messages[indexPath.row]
          let sending = message.from?.id == BotClient.shared.currentUser.id
          switch sending {
          case true:
              let cell = tableView.dequeueReusableCell(withIdentifier: "UserTableViewCell", for: indexPath) as! UserTableViewCell
              cell.transform = tableView.transform
              cell.messageLabel.text = message.text
              return cell
          case false:
                  let cell = tableView.dequeueReusableCell(withIdentifier: "BotTableCell", for: indexPath) as! BotTableCell
                  cell.botMessage.text = message.text
                  cell.botMessage.shouldTrim = !expandedCells.contains(indexPath.row)
                  cell.botMessage.setNeedsUpdateTrim()
                  cell.botMessage.layoutIfNeeded()
                  cell.transform = tableView.transform
                  return cell
              }
          }
  
      override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
              let cell = tableView.dequeueReusableCell(withIdentifier: "BotTableCell", for: indexPath) as! BotTableCell
  
              cell.botMessage.onSizeChange = { [unowned tableView, unowned self] r in
  
                  let point = tableView.convert(r.bounds.origin, from: r)
  
                  guard let indexPath = tableView.indexPathForRow(at: point) else { return }
                  if r.shouldTrim {
                      self.expandedCells.remove(indexPath.row)
                      print("REMOVE CALLED")
                  } else {
                      self.expandedCells.insert(indexPath.row)
                      print("INSERT CALLED")
                  }
                  tableView.reloadData()
              }
          }
  
      override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
          let cell = tableView.dequeueReusableCell(withIdentifier: "BotTableCell", for: indexPath) as! BotTableCell
          cell.botMessage.shouldTrim = !cell.botMessage.shouldTrim
          print("SHOULD TRIM CALLED")
          cell.backgroundColor = .clear
      }
  }
  </code></pre>
  
  <p>Here is my <code>TableViewController</code> Class :</p>
  
  <pre><code>class TMNEMessageViewController: UITableViewController, UITextViewDelegate {
  
      @IBOutlet weak var navBar: UINavigationItem!
      private var observer: AnyObject?
      private var needsUpdateViewOnAppearance = true
      @IBOutlet var messageBar: MessageBar!
      public override var inputAccessoryView: UIView? {return messageBar}
      public override var canBecomeFirstResponder: Bool {return true}
      private var isVisible: Bool {return isViewLoaded &amp;&amp; view.window != nil}
  
      var messages: SortedArray&lt;Activity&gt; { return BotClient.shared.messages }
      var expandedCells = Set&lt;Int&gt;()
  
  
  
      let readMoreTextAttributes: [NSAttributedString.Key: Any] = [
          NSAttributedString.Key.foregroundColor: UIColor.red,
          NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16)
      ]
      let readLessTextAttributes = [
          NSAttributedString.Key.foregroundColor: UIColor.red,
          NSAttributedString.Key.font: UIFont.italicSystemFont(ofSize: 16)
      ]
  
  
  
      override func viewDidLoad() {
          super.viewDidLoad()
          tableView.estimatedRowHeight = 300
          tableView.rowHeight = UITableView.automaticDimension
          registerCells()
          setupObservers()
          tableView.transform = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: 0) //flip tableview
  
          BotClient.shared.start { r in
              if let _ = r.resource {
                  print(r.printResponseData())
              } else if let error = r.error {
                  print("ERROR: " + error.localizedDescription)
                  self.displayError(error.localizedDescription)
              }
          }
      }
  
      override func viewWillAppear(_ animated: Bool) {
          super.viewWillAppear(animated)
          if needsUpdateViewOnAppearance {
              tableView.reloadData()
              needsUpdateViewOnAppearance = false
          }
      }
  
      override func viewDidAppear(_ animated: Bool) {
          super.viewDidAppear(animated)
          becomeFirstResponder()
      }
  
      public override func viewDidLayoutSubviews() {
          super.viewDidLayoutSubviews()
          if tableView.contentInset == UIEdgeInsets.zero {
              updateContentInset(inset: getContentInset())
          }
          // tableView.reloadData()
      }
  
  
      func registerCells() {
          self.tableView.register(UINib(nibName: "BotTableCell", bundle: nil), forCellReuseIdentifier: "BotTableCell")
          self.tableView.register(UINib(nibName: "UserTableViewCell", bundle: nil), forCellReuseIdentifier: "UserTableViewCell")
      }
  
      fileprivate func setupObservers() {
          // Keyboard Notifications
          NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
          NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardDidShowNotification, object: nil)
          NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
          NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardDidHideNotification, object: nil)
          NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
          NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardDidChangeFrameNotification, object: nil)
          // BotClient Notifications
          NotificationCenter.default.addObserver(self, selector: #selector(handleMessageAdded(notification:)), name: .BotClientDidAddMessageNotification, object: BotClient.shared)
      }
  
  
      @objc
      func handleKeyboardNotification(notification: Notification) {
          switch notification.name {
          case UIResponder.keyboardDidChangeFrameNotification:
              if let rect = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
                  DispatchQueue.main.async {
                      //print("r \(rect) i \(self.tableView.safeAreaInsets)")
                      // print(self.tableView.contentInset)
                      let inset = self.tableView.contentInset
                      self.updateContentInset(inset: UIEdgeInsets(top: (rect.height + 10) - self.tableView.safeAreaInsets.top, left: inset.left, bottom: inset.bottom, right: inset.right))
                  }
              }
          default: return
          }
      }
  
      func updateContentInset(inset: UIEdgeInsets) {
          UIView.animate(withDuration: 0.15, animations: {
              self.tableView.contentInset = inset
          }, completion: { f in
              if self.messages.count &gt; 0 {
                  self.tableView.scrollToRow(at: IndexPath.init(row: 0, section: 0), at: .top, animated: true)
              }
          })
      }
  
      @objc func handleMessageAdded(notification: Notification) {
          DispatchQueue.main.async {
              if self.isVisible {
                  self.tableView.reloadData()
              } else {
                  self.needsUpdateViewOnAppearance = true
              }
          }
      }
  
      func getContentInset() -&gt; UIEdgeInsets {
          return UIEdgeInsets(top: max(tableView.safeAreaInsets.top, messageBar.frame.height) - tableView.adjustedContentInset.top, left: 0, bottom: tableView.safeAreaInsets.bottom - tableView.adjustedContentInset.bottom, right: 0)
      }
  
  
      // Err 
      func displayError(_ message: String?) {
  
          let alert = UIAlertController(title: nil, message: message, preferredStyle: UIAlertController.Style.alert)
          alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertAction.Style.default, handler: nil))
          self.present(alert, animated: true, completion: nil)
      }
  }
  </code></pre>