.NET for iOS中RichTextView构造函数重复调用问题排查
问题本质与解决方案
核心原因
你遇到的问题源于**RichTextView(NativeHandle)构造函数的实现不符合.NET for iOS的对象绑定规则**:
- 在.NET for iOS中,
NativeHandle构造函数的设计目的是包装已存在的原生iOS对象,而非创建新对象。当你设置SelectedRange触发原生API调用时,运行时会检查托管对象与原生对象的绑定关系,若发现映射异常,就会尝试通过该构造函数重新生成托管包装。 - 你的所有构造函数(包括
NativeHandle版本)都调用了Initialize方法,这会在每次包装原生对象时重新配置委托、KeyCommands等,直接覆盖之前已设置好的状态,造成“重置”现象。 - 该问题未在Xamarin.iOS中出现,是因为.NET 7的.NET for iOS对托管-原生对象的映射检查更严格,触发了之前未暴露的构造函数实现缺陷。
正确的构造函数实现方式
你需要拆分初始化逻辑,区分创建新对象和包装已有原生对象两种场景:
public class RichTextView : UITextView { // 创建新对象时使用的无参构造函数 public RichTextView() : base() { Initialize(); } // 从NIB/Storyboard加载时的构造函数 public RichTextView(NSCoder coder) : base(coder) { Initialize(); } // 包装已有原生对象的NativeHandle构造函数 public RichTextView(NativeHandle handle) : base(handle) { // 此处禁止调用Initialize! // 原生对象已存在,需保留其现有状态 } // 仅针对新对象的初始化逻辑 private void Initialize() { // 配置委托、KeyCommands等初始化操作 this.Delegate = new RichTextViewDelegate(); this.KeyCommands = new UIKeyCommand[] { ... }; // 其他新对象所需的初始化步骤 } }
关于“空实现”的说明
NativeHandle构造函数的空实现并非hack,而是符合其设计意图:它仅负责建立托管对象与原生对象的绑定,无需修改原生对象状态——此时原生对象已是完整实例(比如你之前通过无参构造函数创建并配置好的实例),重新初始化会破坏已有状态。
额外排查点
- 检查加载对象的函数,确认是否在序列化/反序列化过程中错误重建了托管对象,导致运行时触发重新绑定。
- 确保
RichTextView的所有状态变更都同步到原生对象,避免运行时判定托管-原生对象状态不一致,触发重新绑定逻辑。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

