0

Within the UITableView datasource, I convert an HTML string to NSAttributedString and set it on a label in the cell using the following routine,

class MyCell: UITableViewCell {
    private let bodyLabel = UILabel()
    private var _bodyText = ""
    private var _viewModel = MyCellViewModel()

    var bodyText: String {
        set {
            _bodyText = newValue
            let modifiedFont = String(format:"<span style=\"font-family: '\(Fonts.plexSans)', '\(Fonts.plexSans)'; font-size: 18\">%@</span>", newValue)
            let attrStr = try! NSAttributedString(
                data: modifiedFont.data(using: .utf8, allowLossyConversion: false)!,
                options: [.documentType: NSAttributedString.DocumentType.html,
                          .characterEncoding:String.Encoding.utf8.rawValue],
                documentAttributes: nil)
            bodyLabel.attributedText = attrStr
        }
        get {
            return _bodyText
        }
    }
    
    var viewModel: MyCellViewModel {
        set {
            _viewModel = newValue
            bodyText = newValue.body
        }
        get {
            return _viewModel
        }
    }
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        // does a bunch of straightforward layout constraints etc.
    }

}

extension MyViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellViewModel = modelForIndexPath(indexPath)
        let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.Name, for: indexPath) as! MyCell
            cell.viewModel = cellViewModel
            return cell
    }

This sometimes causes the UITableView to become unstable. Generating an error in the console, Error is "Assert UITableView internal inconsistency prefetchedCells and indexPathsForPrefetchedCells are out of sync.

Sometimes this appeared as a row duplicated, partially drawn row, crash with index out of range.

Found a similar issue in Stackoverflow

HTML strings are simple strings only supporting <br> and <b> tags within text. HTML is short.

The solution presented there worked. I moved the conversion from HTML to NSAttributedString to an earlier step where I'm creating the data for the tableview and moved it out of cellForRowAt.. datasource method.

Why is this a fix? Why would this conversion cause an issue while filling out a UITableViewCell?

David
  • 2,770
  • 5
  • 35
  • 43
  • Why use HTML for this? Why not directly create an `NSAttributedString` with `newValue` and the desired font? You'd probably get much better performance than generating the attributed string from HTML. – HangarRash Apr 24 '23 at 06:03
  • Business requirement. HTML is a convenient form to represent the text coming from a server rather than invent some other encoding for NSAttributedString. Performance is fine. Performance isn't the issue. The corrupted tableview state is the issue. If conversion to NSAttributedString is done outside of cellForRowAt it works fine. The question is why does tableview state get corrupted? – David Apr 24 '23 at 06:10
  • 1
    See https://stackoverflow.com/questions/23926541/how-can-initializing-nsattributedstring-in-tableviewheightforrowatindexpath-be which appears to address your question. – HangarRash Apr 24 '23 at 16:43

0 Answers0