从子控件检测ViewDidUnload

本文关键字:ViewDidUnload 检测 控件 | 更新日期: 2023-09-27 18:03:43

我正试图弄清楚如何在控件的父视图上钩入ViewDidUnload。为了说明我为什么需要这个,考虑一下我的ControlFactory类,它产生UIButton s(在其他控件中):

internal static class ControlFactory
{
        private static readonly IObservable<Unit> sharedDynamicTypeChanged = TinyIoCContainer.Current
            .Resolve<ISystemNotificationsService>()
            .DynamicTypeChanged
            .Publish()
            .RefCount();
        public static UIButton CreateButton()
        {
            return new DynamicTypeAwareButton(sharedDynamicTypeChanged, UIFont.PreferredHeadline);
        }
}

这里的想法是,工厂生产的每个UIButton将根据用户的动态类型设置自动缩放其字体。我的DynamicTypeAwareButton是一个内部类,看起来像这样:

private sealed class DynamicTypeAwareButton : UIButton
{
    private readonly IObservable<Unit> dynamicTypeChanged;
    private readonly UIFont font;
    private IDisposable subscription;
    public DynamicTypeAwareButton(IObservable<Unit> dynamicTypeChanged, UIFont font)
    {
        this.dynamicTypeChanged = dynamicTypeChanged;
        this.font = font;
    }
    public override void MovedToSuperview()
    {
        base.MovedToSuperview();
        // TODO: figure out when to subscribe/unsubscribe
        this.subscription = this.dynamicTypeChanged
            .StartWith(Unit.Default)
            .Subscribe(_ => this.UpdateFont());
    }
    private void UpdateFont()
    {
        this.Font = this.font;
    }
}

问题,正如在评论中所指出的,是我需要知道什么时候按钮的父视图被卸载,以便我可以处置订阅。我可以很容易地访问父视图,但是当父视图被卸载时,我找不到任何钩子来通知。

有人知道有什么方法可以做到这一点吗?

从子控件检测ViewDidUnload

使用WillMoveToSuperView代替MovedToSuperView -它将被调用两次,一次当按钮被添加到视图(即=>订阅),一次当按钮即将被丢弃(其中newSuperview将为null)。

同样,您可以使用SerialDisposable:

将其写得更优雅一些
private sealed class DynamicTypeAwareButton : UIButton
{
    private readonly IObservable<Unit> dynamicTypeChanged;
    private readonly UIFont font;
    private SerialDisposable subscription = new SerialDisposable();
    public override void WillMoveToSuperView(UIView newView)
    {
        base.WillMoveToSuperView();
        // Whenever SerialDisposable.Disposable is assigned, it throws
        // away the previous one. That means, even if the Button gets
        // moved to a new non-null View, we're still not leaking a 
        // subscription
        if (newView != null) 
        {
            this.subscription.Disposable = this.dynamicTypeChanged
                .StartWith(Unit.Default)
                .Subscribe(_ => this.UpdateFont());
        } 
        else 
        {
            this.subscription.Disposable = Disposable.Empty;
        }
    }
    public void UpdateFont()
    {
        /* ... */
    }
}