You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CTRun及CTRunGetPositions相关崩溃问题:不同iOS版本阈值差异咨询

问题原因与解决方案

崩溃根源

你的代码调用CTRunGetPositions时存在核心错误:

  • 在Core Text的语义中,CFRange(location: 0, length: 0)表示获取从位置0到run末尾的所有字形位置,而非单个位置。
  • 你仅分配了单个CGPoint的内存(var truncationPosition = CGPoint.zero),当truncationRun的字形数量超过1时,CTRunGetPositions会向该指针后方的内存写入数据,直接造成内存越界写入,破坏栈上的其他数据。

这种越界不会立刻触发崩溃,而是等到函数执行结束、栈帧销毁时才暴露。不同iOS系统阈值有差异,是因为各系统的栈布局、内存保护机制严格程度不同,对越界写入的容忍度存在区别。

修复方案

需根据truncationRun的实际字形数量,分配足够空间存储位置数据。以下两种方案可根据你的需求选择:

方案1:仅获取第一个字形的位置(匹配原代码意图)

func testFunc() {
 // ......
 let runs = CTLineGetGlyphRuns(finalLine) as! [CTRun]
 if let truncationRun = runs.last {
     var truncationPosition = CGPoint.zero
     // 指定length为1,仅获取第一个字形的位置
     CTRunGetPositions(truncationRun, CFRange(location: 0, length: 1), &truncationPosition)
     var truncationAscent: CGFloat = 0, truncationDescent: CGFloat = 0
     let truncationWidth = CTRunGetTypographicBounds(truncationRun, CFRange(location: 0, length: 0), &truncationAscent, &truncationDescent, nil)
     // ......
 }
 // ......
}

方案2:获取所有字形的位置

func testFunc() {
 // ......
 let runs = CTLineGetGlyphRuns(finalLine) as! [CTRun]
 if let truncationRun = runs.last {
     let glyphCount = CTRunGetGlyphCount(truncationRun)
     // 分配对应数量的CGPoint数组
     var positions = Array(repeating: CGPoint.zero, count: glyphCount)
     CTRunGetPositions(truncationRun, CFRange(location: 0, length: 0), &positions)
     var truncationAscent: CGFloat = 0, truncationDescent: CGFloat = 0
     let truncationWidth = CTRunGetTypographicBounds(truncationRun, CFRange(location: 0, length: 0), &truncationAscent, &truncationDescent, nil)
     // ......
 }
 // ......
}

补充说明

CTRunGetTypographicBounds使用CFRange(location:0, length:0)是合理的,该函数在length为0时会返回整个run的排版边界,仅通过指针返回单个数值,无需额外分配空间。

内容的提问来源于stack exchange,提问作者MangaK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 22:26:12