我有一个类似静态的(发布者生命周期=应用程序生命周期)事件,我需要从视图中订阅。我无法可靠地确定何时导航视图(在Xamarin.Forms NavigationPage中按下导航栏后退按钮就是一个示例),因此我无法确定视图何时应取消订阅observable。 (我知道可以在OnAppearing / OnDisappearing中订阅/取消订阅,但这会带来一系列问题我不会在这里详细介绍。)
因此,我发现自己需要让视图对事件略微订阅,即允许视图被垃圾收集而不必取消订阅事件。理想情况下,我喜欢可以在bold
或function preloader(){
$('.preloader').delay(800).fadeOut('slow');
}
$(preloader);
$(document).on("turbolinks:load", preloader);
或简称myObj.myEvent |> Observable.AsWeak |> Observable.Subscribe ...
的行中使用的内容。
不幸的是我不知道如何实现这一点。我听说过System.WeakReference课程,但这对我来说都是全新的,我不知道如何正确使用它 - 我见过的大多数例子对于我尝试过的事情似乎过于复杂要做,这意味着要么我想要一些不同的东西,要么表面下面还有比我怀疑的更多的陷阱。
如何在允许订阅者进行垃圾收集而不取消订阅的情况下订阅F#中的事件/可观察对象?
类似但不重复的问题:
答案 0 :(得分:2)
我已经找到了一个看似正常工作的相对简单的功能,虽然我不知道自己在做什么,所以我已经把它放在Code Review SE。它基于Samuel Jack的Weak Events in .Net, the easy way信息以及CodeProject Weak Events in C#中的解决方案4。
module Observable =
open System
// ('a -> 'b -> unit) -> 'a -> IObservable<'b>
let subscribeWeakly callback target source =
let mutable sub:IDisposable = null
let mutable disposed = false
let wr = new WeakReference<_>(target)
let dispose() =
lock (sub) (fun () ->
if not disposed then sub.Dispose(); disposed <- true)
let callback' x =
let isAlive, target = wr.TryGetTarget()
if isAlive then callback target x else dispose()
sub <- Observable.subscribe callback' source
sub
请参阅下面的WeakSubscriber
类型。
您必须使用回调&#39; me
参数来调用相关方法。如果您在回调中使用this
,则由于上述文章中描述的原因,您仍然会得到强有力的参考。出于同样的原因(我猜?),你不能调用&#34;普通&#34;使用let
定义的类中的函数。 (但是,您可以将方法定义为private
。)
助手班:
type Publisher() =
let myEvent = new Event<_>()
[<CLIEvent>] member this.MyEvent = myEvent.Publish
member this.Trigger(x) = myEvent.Trigger(x)
type StrongSubscriber() =
member this.MyMethod x =
printfn "Strong: method received %A" x
member this.Subscribe(publisher:Publisher) =
publisher.MyEvent |> Observable.subscribe this.MyMethod
publisher.MyEvent |> Observable.subscribe
(fun x -> printfn "Strong: lambda received %A" x)
type WeakSubscriber() =
member this.MyMethod x =
printfn "Weak: method received %A" x
member this.Subscribe(publisher:Publisher) =
publisher.MyEvent |> Observable.subscribeWeakly
(fun (me:WeakSubscriber) x -> me.MyMethod x) this
publisher.MyEvent |> Observable.subscribeWeakly
(fun _ x -> printfn "Weak: lambda received %A" x) this
实际测试:
[<EntryPoint>]
let main argv =
let pub = Publisher()
let doGc() =
System.GC.Collect()
System.GC.WaitForPendingFinalizers()
System.GC.Collect()
printfn "\nGC completed\n"
let someScope() =
let strong = StrongSubscriber()
let weak = WeakSubscriber()
strong.Subscribe(pub)
weak.Subscribe(pub)
doGc() // should not remove weak subscription since it's still in scope
printfn "All subscribers should still be triggered:"
pub.Trigger(1)
someScope()
doGc() // should remove weak subscriptions
printfn "Weak subscribers should not be triggered:"
pub.Trigger(2)
System.Console.ReadKey() |> ignore
0
输出:
GC completed
All subscribers should still be triggered:
Strong: method received 1
Strong: lambda received 1
Weak: method received 1
Weak: lambda received 1
GC completed
Weak subscribers should not be triggered:
Strong: method received 2
Strong: lambda received 2