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

macOS 14.x.x下UITextView(Mac Catalyst)选中文本替换Bug求助

macOS 14.x.x + TextKit1 下 Mac Catalyst UITextView 多行选中文本替换Bug分析与修复

Bug现象

从macOS 14.x.x版本起,使用TextKit1的Mac Catalyst环境中,UITextView在选中多行文本时会触发异常:选中行内的部分文本会被选中区域内的另一部分文本意外替换。

复现步骤

  1. 在UITextView中填入以下文本:
Carnaroli, Maratelli, or Vialone Nano are best
Vialone Nano cooks quickly – watch it! It also absorbs condiments nicely.
Avoid Baldo, Originario, Ribe and Roma
  1. 使用光标拖拽或Shift+箭头键选中上述三行文本,即可观察到文本被替换的异常。
  2. 按Command-Z撤销后,可重复触发该Bug。

Bug细节

  • 具体替换示例:第二行的「e Nano cooks quickly – 」会被替换为第三行的「Baldo, Originario, Ribe」
  • 触发场景具有特定性,并非所有字符串或选中操作都会出现,但符合触发条件时可稳定复现
  • iOS原生环境无此问题,剪贴板内容不影响Bug触发
  • 多次触发后可能会自行停止出现

Bug表现截图

  • 选中前:三行文本完整显示,无异常
  • 选中后:第二行部分文本被第三行内容替换,显示异常

复现代码

自定义TextKit组件的复现代码

@interface TestNoteViewController ()

@end

@implementation TestNoteViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self createTextView];
}

- (void)createTextView {
    
    NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:self.note.text
                                                                     attributes:nil];
    
    NSTextStorage *textStorage = [NSTextStorage new];
    [textStorage appendAttributedString:attrString];
    
    CGRect newTextViewRect = self.view.bounds;
    
    // 创建布局管理器
    NSLayoutManager *layoutManager = [NSLayoutManager new];
    [textStorage addLayoutManager:layoutManager];
    
    // 创建文本容器
    NSTextContainer *container = [[NSTextContainer alloc] initWithSize:CGSizeMake(newTextViewRect.size.width, CGFLOAT_MAX)];
    [layoutManager addTextContainer:container];
    
    
    // 创建并添加文本视图
    UITextView *textView = [[UITextView alloc] initWithFrame:newTextViewRect
                                               textContainer:container];
    [self.view addSubview:textView];
    textView.translatesAutoresizingMaskIntoConstraints = NO;
    UILayoutGuide *safeArea = textView.superview.safeAreaLayoutGuide;
    [textView.leadingAnchor constraintEqualToAnchor:safeArea.leadingAnchor].active = YES;
    [textView.trailingAnchor constraintEqualToAnchor:safeArea.trailingAnchor].active = YES;
    [textView.topAnchor constraintEqualToAnchor:safeArea.topAnchor].active = YES;
    [textView.bottomAnchor constraintEqualToAnchor:textView.superview.bottomAnchor].active = YES;
}

@end

无需自定义TextKit组件的复现代码(同样触发Bug)

@interface TestNoteViewController ()

@end

@implementation TestNoteViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self createTextView];
}

- (void)createTextView {
    
    UITextView *textView = [UITextView new];
    textView.text = self.note.text;
    [self.view addSubview:textView];
    textView.translatesAutoresizingMaskIntoConstraints = NO;
    UILayoutGuide *safeArea = textView.superview.safeAreaLayoutGuide;
    [textView.leadingAnchor constraintEqualToAnchor:safeArea.leadingAnchor].active = YES;
    [textView.trailingAnchor constraintEqualToAnchor:safeArea.trailingAnchor].active = YES;
    [textView.topAnchor constraintEqualToAnchor:safeArea.topAnchor].active = YES;
    [textView.bottomAnchor constraintEqualToAnchor:textView.superview.bottomAnchor].active = YES;
}

@end

原因分析

这是macOS 14.x.x版本中Mac Catalyst对TextKit1的适配Bug,核心问题在于UITextView处理多行选中时,NSTextStorage的范围计算出现错误,导致布局管理器(NSLayoutManager)同步选中状态与文本内容时,混淆了不同位置的文本索引,触发了意外的文本覆盖操作。

修复方案

  1. 升级到TextKit2:TextKit2是苹果新一代文本框架,在macOS 14及后续版本中对Mac Catalyst的支持更完善,替换TextKit1组件即可规避该Bug。需将NSTextStorage、NSLayoutManager、NSTextContainer替换为NSTextContentStorage、NSTextLayoutManager、NSTextContainer,同时调整UITextView的初始化逻辑。
  2. 临时规避方案:若无法立即升级TextKit2,可通过监听UITextView的选中状态变化,手动校验文本完整性:实现UITextViewDelegate的textViewDidChangeSelection:方法,在选中操作后对比当前文本与原始文本,若发现异常则恢复原始内容。
  3. 等待系统补丁:该Bug属于系统级适配问题,苹果大概率会在后续macOS更新中修复,可关注系统更新并及时升级。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:04:55