facebook / lexical-ios

Lexical iOS is an extensible text editor framework that integrates the APIs and philosophies from Lexical Web with a Swift API built on top of TextKit.
MIT License
549 stars 41 forks source link

Crash when typing in a lexical view which has decorators: Terminating app due to uncaught exception 'NSInternalInconsistencyException' #34

Open MilesV64 opened 1 year ago

MilesV64 commented 1 year ago

After inserting a custom decorator into the document and then typing more, I get the following crash:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[Lexical.LayoutManager _fillLayoutHoleForCharacterRange:desiredNumberOfLines:isSoft:] *** attempted layout while textStorage is editing. It is not valid to cause the layoutManager to do layout while the textStorage is editing (ie the textStorage has been sent a beginEditing message without a matching endEditing.)'

The crash is on line 544 of Editor: frontend?.layoutManager.invalidateLayout(forCharacterRange: rangeCacheItem.range, actualCharacterRange: nil)

This makes me very nervous to use the library in production, any advice on how to avoid this crash?

Here's the JSON of my lexical right before the crash (I was printing after every edit):

{
  "root": {
    "direction": null,
    "format": "",
    "indent": 0,
    "type": "root",
    "children": [
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "Test  niceee ",
            "version": 1,
            "type": "text"
          },
          {
            "type": "timestamp",
            "version": 1,
            "timestamp": 34.43114
          },
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": " ",
            "version": 1,
            "type": "text"
          }
        ],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "New line fdsa ",
            "version": 1,
            "type": "text"
          },
          {
            "type": "timestamp",
            "version": 1,
            "timestamp": 34.43114
          }
        ],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "E",
            "version": 1,
            "type": "text"
          }
        ],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "Weeeeee",
            "version": 1,
            "type": "text"
          }
        ],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "Weeee",
            "version": 1,
            "type": "text"
          }
        ],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "Da",
            "version": 1,
            "type": "text"
          }
        ],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "Test ",
            "version": 1,
            "type": "text"
          },
          {
            "type": "timestamp",
            "version": 1,
            "timestamp": 34.43114
          },
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": " ",
            "version": 1,
            "type": "text"
          },
          {
            "format": 1,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "tello",
            "version": 1,
            "type": "text"
          }
        ],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "F",
            "version": 1,
            "type": "text"
          }
        ],
        "version": 1
      },
      {
        "direction": null,
        "format": "",
        "indent": 0,
        "type": "paragraph",
        "children": [
          {
            "format": 0,
            "detail": 0,
            "style": "",
            "mode": "normal",
            "text": "F",
            "version": 1,
            "type": "text"
          }
        ],
        "version": 1
      }
    ],
    "version": 1
  }
}
amyworrall commented 1 year ago

Hi Miles. I'm very sorry about the crash. Firstly, can you confirm which version of Lexical you're using? (If it's not a released version, which commit you've checked out of GitHub?) I ask because I did fix a similar bug recently.

Secondly, can you tell me if you're using Lexical APIs from a background thread? In my experience, this kind of TextKit issue can sometimes be an issue with concurrent use across threads. (And if you're using LexicalView to as your Lexical frontend, all TextKit access must be done on the main thread, because UITextView assumes it can access our TextKit stack on the main thread whenever it likes.)

I'm not ruling out a bug in Lexical, I just want to get an idea of where to look!

Regarding the stability of decorator nodes: I'm using them in production with the read-only frontend for Lexical, as part of powering News Feed on the Workplace app. I'm going to ship some decorators in editable Lexical in the Workplace composer later this year. Obviously they'll get a bunch of further QA when I ship them on a surface.