Why does NSLayoutManager's text height/lines calculation differ from UILabel's behavior with different line break modes?

We are curious about what caused the mismatch between UILabel rendering and NSLayoutManager calculation with different lineBreakMode. Can we say that NSLayoutManager doesn't support lineBreakMode except .byWordWrapping?

First, we have a function that creates an attributed string. In this function, we assign .byTruncatingTail to the paragraphStyle lineBreakMode.

func createAttributedString(with text: String) -> NSMutableAttributedString {
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineBreakMode = .byTruncatingTail
    let attributedString = NSMutableAttributedString(string: text,
                                                     attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 35),
                                                                  NSAttributedString.Key.paragraphStyle: paragraphStyle])
    return attributedString
}

If we create a label with the following settings:

let text = (1..<20).reduce("", { "\($0)" + "\($1)-"})
let attributedString = createAttributedString(with: text)
let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 500)))
label.numberOfLines = 0
label.lineBreakMode = .byTruncatingTail
label.attributedText = attributedString

we get the result:

If we use the same attributed string maker function and use NSLayoutManager to calculate the height for a certain width with the following code reference from Apple's documentation:

let text = (1..<20).reduce("", { "\($0)" + "\($1)-"})
let attributedString = createAttributedString(with: text)

let textContainer = NSTextContainer(size: CGSize(width: 100, height: CGFloat.greatestFiniteMagnitude))
let layoutManager = NSLayoutManager()
let textStorage = NSTextStorage(attributedString: attributedString)

layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)

textContainer.lineFragmentPadding = 0.0
textContainer.maximumNumberOfLines = 0
textContainer.lineBreakMode = .byTruncatingTail

layoutManager.ensureLayout(for: textContainer)
layoutManager.glyphRange(for: textContainer)
let textFrame = layoutManager.usedRect(for: textContainer)
print("textSize: \(textFrame.size)")

we get the print result:

If we assign the calculated rect to the label, we get:

This result does not match the initial label we created.

If we change the lineBreakMode in the attributed string maker to the default value, .byWordWrapping, we can get the result for multiple lines, which has the same height as the initial label.

If we assign the calculated rect to the label, we get:

We are curious about what caused the mismatch between UILabel rendering and NSLayoutManager calculation with different lineBreakMode. Can we say that NSLayoutManager doesn't support lineBreakMode except .byWordWrapping?

We are also curious about the design thought behind having the default lineBreakMode for UILabel be .byTruncatingTail and for NSMutableParagraphStyle be .byWordWrapping.