UITextView插入NSTextAttachment图片CPU过高、UI卡顿问题求助
问题根源
现有代码的核心性能损耗来自以下几个问题:
- 重复执行文本插入逻辑:你已经手动调用
txtViewShow.textStorage.replaceCharacters修改了文本内容,最后仍然返回true,会触发系统默认的文本插入行为,等于同一段范围执行了两次修改操作,冗余计算直接拉高CPU占用 - 图片无缓存重复解码:每次匹配到对应文本都要从
Data实时解码生成UIImage,图片解码是CPU密集型操作,多次触发会占用大量CPU资源 - 未限制文本附件尺寸:没有给
NSTextAttachment设置固定bounds,UITextView渲染时会每次实时计算图片的显示尺寸,插入图片越多重复计算量越大 - 遍历匹配效率低:每次输入都遍历整个
arrDataModel数组做匹配,数组元素多的时候会产生不必要的遍历开销
优化方案
1. 修正回调返回值
手动修改textStorage后直接返回false,阻止系统执行默认插入逻辑,避免重复修改文本
2. 提前缓存解码后的UIImage
在arrDataModel初始化时就把imageData转成UIImage并缓存,避免每次插入时重复解码
3. 固定NSTextAttachment显示尺寸
插入附件前提前设置好bounds属性,避免渲染时实时计算
4. 优化匹配逻辑
把arrDataModel的匹配规则改成字典映射,用textDefaul作为key,对应的数据模型作为value,O(1)复杂度匹配无需遍历数组
优化后示例代码
// 提前在外部做好字典映射和图片缓存,不用每次输入都计算 lazy var textMapping: [String: UIImage] = { var map = [String: UIImage]() for data in arrDataModel { guard let image = UIImage(data: data.imageData) else { continue } // 提前把图片缩放到需要的尺寸,缓存处理后的结果 let targetSize = CGSize(width: 20, height: 20) // 自行调整目标显示尺寸 UIGraphicsBeginImageContextWithOptions(targetSize, false, UIScreen.main.scale) image.draw(in: CGRect(origin: .zero, size: targetSize)) let scaledImage = UIGraphicsGetImageFromCurrentImageContext() ?? image UIGraphicsEndImageContext() map[data.textDefaul] = scaledImage } return map }() func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { // 直接用字典匹配,无需遍历数组 guard let matchedImage = textMapping[text] else { return true } let attachment = NSTextAttachment() attachment.image = matchedImage // 提前设置固定尺寸,避免渲染时实时计算,y值调整适配字体基线 attachment.bounds = CGRect(x: 0, y: -4, width: 20, height: 20) let attString = NSAttributedString(attachment: attachment) // 修改文本前记录光标位置,修改后手动恢复避免光标跳变 let targetSelectedRange = NSRange(location: range.location + 1, length: 0) textView.textStorage.replaceCharacters(in: range, with: attString) textView.selectedRange = targetSelectedRange // 手动修改完成后返回false,阻止系统默认插入逻辑 return false }
内容的提问来源于stack exchange,提问作者Sasaki
相关产品推荐
相关产品推荐

