使用TThread.ForceQueue延时调用时如何检测TFrame对象是否已被释放
Delphi TFrame异步延时回调的存活检测方案
以下是该场景下3种经过验证的可靠处理机制:
方案1:自定义销毁标记位(兼容性最好,全版本Delphi适用)
TFrame继承自TComponent,你可以给Frame类新增私有标记字段记录销毁状态,回调执行前先做校验:// 类定义部分 type TMyFrame = class(TFrame) private FIsDestroying: Boolean; protected procedure BeforeDestruction; override; public procedure OneProc; end; // 重写销毁前的触发方法 procedure TMyFrame.BeforeDestruction; begin FIsDestroying := True; inherited; end; // 回调方法开头先做存活校验 procedure TMyFrame.OneProc; begin // 不要只判断Assigned(Self),野指针场景下Assigned会返回误判的True if not Assigned(Self) or FIsDestroying then Exit; // 后续正常业务逻辑 end;方案2:弱引用包装(适用于Delphi 10.4及以上版本,侵入性最低)
高版本Delphi支持非ARC对象的弱引用包装,调用队列时直接把Frame的弱引用传入闭包,执行前判断引用有效性即可,不需要修改Frame类的原有代码:// 调用ForceQueue的逻辑 var WeakFrame := TWeakReference<TMyFrame>.Create(MyFrame); TThread.ForceQueue(nil, procedure var CurrFrame: TMyFrame; begin CurrFrame := WeakFrame.Get; if Assigned(CurrFrame) then CurrFrame.OneProc; end, 200);方案3:销毁前主动清除队列回调(根源性避免无效调用)
你可以在Frame销毁逻辑中调用TThread.RemoveQueuedEvents,直接移除队列中还未执行的当前Frame的回调任务,从源头减少无效触发的概率:procedure TMyFrame.BeforeDestruction; begin // 移除队列中所有关联当前OneProc的待执行任务 TThread.RemoveQueuedEvents(nil, OneProc); inherited; end;
最佳实践推荐方案1+方案3组合使用:既可以提前清除待执行的无效回调,又能在极端场景(比如回调已经启动执行时才触发销毁)下拦截非法对象访问,稳定性最高。
内容的提问来源于stack exchange,提问作者zeus
相关产品推荐
相关产品推荐

