instacart / Nantes

Swift TTTAttributedLabel replacement
Apache License 2.0
1.11k stars 85 forks source link

crash on Truncation.swift:57 let originalLine = lines[originalIndex] #40

Closed cdoky closed 5 years ago

cdoky commented 5 years ago

// numberOfLines = 0 // tokenLines.count = 1 // index = 0 // originalIndex = -1 Truncation.swift:49 let originalIndex = self.numberOfLines - tokenLines.count + index

crash on Truncation.swift:57 let originalLine = lines[originalIndex]

(lldb) po tokenLines
▿ 1 element
  - 0 : <CTLine: 0x6000034b0000>{run count = 1, string range = (0, 1), width = 13, A/D/L = 12.72/4.08/0, glyph count = 1, runs = (

<CTRun: 0x7fe4fad6ffc0>{string range = (0, 1), string = "\u2026", attributes = {
    NSColor = "UIExtendedSRGBColorSpace 0.4 0.368627 1 1";
    NSFont = "<UICTFont: 0x7fe4fad2e020> font-family: \"PingFangSC-Regular\"; font-weight: normal; font-style: normal; font-size: 12.00pt";
    NSKern = 1;
    NSParagraphStyle = "Alignment 4, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0";
}}

)
}
mdilaveroglu commented 5 years ago

+1

cdoky commented 5 years ago

@mdilaveroglu if you have not solution,you can use mine

ngoleo commented 5 years ago

@philCc could you include your solution?

cdoky commented 5 years ago

@ngocholo

...
// Truncation.swift:48
        for (index, tokenLine) in tokenLines.enumerated() {
            let originalIndex = self.numberOfLines - tokenLines.count + index

            // We want to replace every other line besides the first truncated line completely with the lines from the truncation token
            if originalIndex < 0 {
                continue
            }
            guard index == 0 else {
                lines[originalIndex] = tokenLine
                continue
            }
...
chansen22 commented 5 years ago

@philCc @mdilaveroglu do either of you have an example of how to get this to happen? I see we can band-aid it by skipping any elements that are outside the index and we should probably add some defense there, but I'd like to understand how we get into this case better, since it points that something else with the truncation code is wrong.

guyueming commented 5 years ago

@chansen22 init with label.lineBreakMode = .byTruncatingTail,but then setAttributedText with paragraphStyle.lineBreakMode = .byWordWrapping

chansen22 commented 5 years ago

@guyueming I tried with just creating the label, setting its lineBreak mode and then setting the attributedString with a paragraph style that was just .byWordWrapping, but had no luck. The code I pasted is a combo of the info inside @philCc's debugger output, but I can't get it to crash. Can you share a direct example of how you get this to occur? The setup + the string used?

        let label: NantesLabel = .init(frame: CGRect(x: 5, y: 40, width: 5, height: 20))
        label.kern = 1.0
        label.lineBreakMode = .byTruncatingTail
        let paragraph = NSMutableParagraphStyle()
        paragraph.lineBreakMode = .byWordWrapping
        paragraph.paragraphSpacing = 0
        paragraph.alignment = NSTextAlignment(rawValue: 4)!
        paragraph.lineSpacing = 1
        paragraph.paragraphSpacingBefore = 0
        paragraph.headIndent = 0
        paragraph.tailIndent = 0
        paragraph.firstLineHeadIndent = 0
        paragraph.lineHeightMultiple = 0
        paragraph.baseWritingDirection = NSWritingDirection(rawValue: -1)!
        let attributedText = NSAttributedString(string: "\u{2026}", attributes: [NSAttributedString.Key.paragraphStyle: paragraph])
        label.attributedText = attributedText
        view.addSubview(label)
guyueming commented 5 years ago

@chansen22

        let label: NantesLabel = .init(frame: CGRect(x: 5, y: 40, width: 5, height: 20))
        label.numberOfLines = 0
        label.kern = 1.0
        label.lineBreakMode = .byTruncatingTail
        let paragraph = NSMutableParagraphStyle()
        paragraph.lineBreakMode = .byWordWrapping
        paragraph.paragraphSpacing = 0
        paragraph.alignment = NSTextAlignment(rawValue: 4)!
        paragraph.lineSpacing = 1
        paragraph.paragraphSpacingBefore = 0
        paragraph.headIndent = 0
        paragraph.tailIndent = 0
        paragraph.firstLineHeadIndent = 0
        paragraph.lineHeightMultiple = 0
        paragraph.baseWritingDirection = NSWritingDirection(rawValue: -1)!
        let attributedText = NSAttributedString(string: "The text is long enough to be wrapped", attributes: [NSAttributedString.Key.paragraphStyle: paragraph])
        label.attributedText = attributedText
        view.addSubview(label)