Утечка подписок ReactiveUI? - PullRequest
       15

Утечка подписок ReactiveUI?

7 голосов
/ 19 января 2012

Я смотрел на примеры ReactiveUi из блогов, и мне интересно, есть ли в ReactiveUI какое-то средство управления подписками или эти примеры игнорируют тот факт, что они могут пропускать подписки?

Каждый раз, когда я вызываю метод в ReactiveUi, который приводит к IDisposable, нужно ли мне удерживать эту ссылку и отслеживать ее самостоятельно? Кроме того, означает ли это, что мои ViewModels должны быть одноразовыми, это кажется трудным, поскольку мы не знаем, когда исчезнут связанные «Views» (т. Е. Если моя ViewModel отражает элементы в сетке данных) в WPF, поэтому, кажется, не подходит место для вызова утилизировать.

Ответы [ 3 ]

14 голосов
/ 26 января 2012

Вы также должны помнить, что IDisposables, возвращаемые Rx и ReactiveUI, не связаны с неуправляемой памятью - это всего лишь простые объекты .NET, все еще проверяемые сборщиком мусора.

Большинство подписок, которые вы делаете в конструкторах ваших ReactiveObjects, будут привязаны к времени жизни хост-объекта - поэтому, когда он выходит за пределы области действия и подчиняется GC, так же как и все подписки, CLR обнаружит круговая ссылка и просто все обстреливают.

Как упоминает Enigmativity, один хитрый момент - это когда вы используете FromEventPattern, чтобы связать время жизни подписки (и, возможно, ViewModel) с временем жизни объекта WPF. Тем не менее, я бы поспорил, если вы часто используете FromEventPattern в ReactiveUI, вы определенно делаете Doing It Wrong ™.

RxUI - это все о ViewModels, а ViewModels - это о командах и свойствах (и о том, как свойства связаны друг с другом), так что вы можете проверить поведение опыта пользователя отдельно от его визуальных эффектов.

11 голосов
/ 19 января 2012

Вам нужно только хранить ссылки на IDisposable, возвращаемые подписками, если вам нужно отписаться рано от наблюдаемой. Наблюдаемые, естественно, будут вызывать Dispose, когда они завершаются сообщениями OnCompleted или OnError.

Однако вам необходимо сохранять ссылки, когда у вас есть бесконечная наблюдаемая подписка (т. Е. FromEventPattern), но это точно так же, как необходимость удалять обработчики событий перед закрытием формы / представления.

2 голосов
/ 26 марта 2013

Просто чтобы быть в безопасности, я буду использовать этот паттерн с этого момента.Я, вероятно, изменю работу с помощью методов расширения, но принцип здравыйЧтобы быть уверенным, что вы не утечки подписок, вы хотите удалить их

class Mesh2D{

    public Mesh2D()
    {
        DisposeOnUnload(CreateBindings());
    }

    // Register all disposables for disposal on
    // UIElement.Unload event. This should be
    // moved to an extension method.
    void DisposeOnUnload(IEnumerable<IDisposable> disposables)
    {
        var d = new CompositeDisposable(disposables);
        var d2 = this.UnloadedObserver()
            .Subscribe(e => d.Dispose());
        var d3 = this.Dispatcher.ShutdownStartedObserver()
            .Subscribe(e => d.Dispose());
        d.Add(d2);
        d.Add(d3);
    }

    // Where your bindings are simply yielded and
    // they are removed on Unload magically
    IEnumerable<IDisposable> CreateBindings()
    {
        // When the size changes we need to update all the transforms on 
        // the markers to reposition them. 
        yield return this.SizeChangedObserver()
            .Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler)
            .Subscribe(eventArgs => this.ResetImageSource());

        // If the points change or the viewport changes
        yield return this.WhenAny(t => t.Mesh, t => t.Viewport, (x, t) => x.Value)
            .Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler)
            .Subscribe(t => this.UpdateMeshChanged());
    }
}

Примечание. Я обертываю RX FromEventPattern автоматически сгенерированными методами расширения, поэтому я получаю SizeChangedObserver () и UnloadedObserver () бесплатно, а неТрудно запомнить формат FromEventPattern.

Код переноса генерируется таким образом:

public static IObservable<EventPattern<RoutedEventArgs>> UnloadedObserver(this FrameworkElement This){
    return Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(h => This.Unloaded += h, h => This.Unloaded -= h);
}

Приведенный выше шаблон, вероятно, можно использовать и для отсоединения моделей представления IDisposable.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...