Optimize NSActionDispatcher usage (#4162)
* [NSActionDispatcher] Remove unused class * [NSActionDispatcher] Move selectorname and selector variable into each class * [NSActionDispatcher] Add specialized versions of NSActionDispatcher that use SynchronizationContext parameters * [NSObject] Add specialized overloads for *InvokeOnMainThread which use SynchronizationContext parameters * [AppKit,UIKit] Use the synchronization context specialized versions of *InvokeOnMainThread This finishes the PR adding the following value: 1. There is no Action wrapper being constructed on async continuations, thus on every await call we gain: 1 less allocation (lambda capture), 1 less indirected call to the actual continuation, and possibly Action being removed by the linker, as its no longer used. 2. NSActionDispatcher* classes might now be linked out, due to the static selector no longer being used everywhere 3. One unused class removed * PR feedback * Fix build * PR feedback 2 * Seal this class * Fix some renames not followed because they were undef ifdef'd code
This commit is contained in:
Родитель
d5263edd69
Коммит
0dd3dece90
|
@ -14,12 +14,12 @@ namespace AppKit {
|
|||
|
||||
public override void Post (SendOrPostCallback d, object state)
|
||||
{
|
||||
NSRunLoop.Main.BeginInvokeOnMainThread (() => d (state));
|
||||
NSRunLoop.Main.BeginInvokeOnMainThread (d, state);
|
||||
}
|
||||
|
||||
public override void Send (SendOrPostCallback d, object state)
|
||||
{
|
||||
NSRunLoop.Main.InvokeOnMainThread (() => d (state));
|
||||
NSRunLoop.Main.InvokeOnMainThread (d, state);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,17 +24,31 @@
|
|||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using ObjCRuntime;
|
||||
|
||||
namespace Foundation {
|
||||
|
||||
#if !COREBUILD
|
||||
// Use this for synchronous operations
|
||||
[Register ("__MonoMac_NSActionDispatcher")]
|
||||
internal sealed class NSActionDispatcher : NSObject {
|
||||
internal abstract class NSDispatcher : NSObject
|
||||
{
|
||||
public const string SelectorName = "xamarinApplySelector";
|
||||
public static readonly Selector Selector = new Selector (SelectorName);
|
||||
|
||||
protected NSDispatcher ()
|
||||
{
|
||||
IsDirectBinding = false;
|
||||
}
|
||||
|
||||
[Export (SelectorName)]
|
||||
[Preserve (Conditional = true)]
|
||||
public abstract void Apply ();
|
||||
}
|
||||
|
||||
// Use this for synchronous operations
|
||||
[Register ("__MonoMac_NSActionDispatcher")]
|
||||
internal sealed class NSActionDispatcher : NSDispatcher {
|
||||
readonly Action action;
|
||||
|
||||
public NSActionDispatcher (Action action)
|
||||
|
@ -43,40 +57,28 @@ namespace Foundation {
|
|||
throw new ArgumentNullException ("action");
|
||||
|
||||
this.action = action;
|
||||
IsDirectBinding = false;
|
||||
}
|
||||
|
||||
[Export (SelectorName)]
|
||||
[Preserve (Conditional = true)]
|
||||
public void Apply ()
|
||||
{
|
||||
action ();
|
||||
}
|
||||
public override void Apply () => action ();
|
||||
}
|
||||
|
||||
// Use this for synchronous operations
|
||||
[Register ("__MonoMac_ActionDispatcher")]
|
||||
internal sealed class ActionDispatcher : NSObject {
|
||||
public const string SelectorName = "xamarinApplySelector";
|
||||
public static readonly Selector Selector = new Selector (SelectorName);
|
||||
[Register ("__MonoMac_NSSynchronizationContextDispatcher")]
|
||||
internal sealed class NSSynchronizationContextDispatcher : NSDispatcher
|
||||
{
|
||||
readonly SendOrPostCallback d;
|
||||
readonly object state;
|
||||
|
||||
readonly Action action;
|
||||
|
||||
public ActionDispatcher (Action action)
|
||||
public NSSynchronizationContextDispatcher (SendOrPostCallback d, object state)
|
||||
{
|
||||
if (action == null)
|
||||
throw new ArgumentNullException ("action");
|
||||
if (d == null)
|
||||
throw new ArgumentNullException (nameof (d));
|
||||
|
||||
this.action = action;
|
||||
IsDirectBinding = false;
|
||||
this.d = d;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
[Export (SelectorName)]
|
||||
[Preserve (Conditional = true)]
|
||||
public void Apply ()
|
||||
{
|
||||
action ();
|
||||
}
|
||||
public override void Apply () => d (state);
|
||||
}
|
||||
|
||||
// Used this for NSTimer support
|
||||
|
@ -104,41 +106,80 @@ namespace Foundation {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class NSAsyncDispatcher : NSDispatcher {
|
||||
readonly GCHandle gch;
|
||||
|
||||
protected NSAsyncDispatcher ()
|
||||
{
|
||||
gch = GCHandle.Alloc (this);
|
||||
}
|
||||
|
||||
public override void Apply ()
|
||||
{
|
||||
gch.Free ();
|
||||
|
||||
//
|
||||
// Although I would like to call Dispose here, to
|
||||
// reduce the load on the GC, we have some useful diagnostic
|
||||
// code in our runtime that is useful to track down
|
||||
// problems, so we are removing the Dispose and letting
|
||||
// the GC and our pipeline do their job.
|
||||
//
|
||||
#if MONOTOUCH
|
||||
// MonoTouch has fixed the above problems, and we can call
|
||||
// Dispose here.
|
||||
Dispose ();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Use this for asynchronous operations
|
||||
[Register ("__MonoMac_NSAsyncActionDispatcher")]
|
||||
internal class NSAsyncActionDispatcher : NSObject {
|
||||
GCHandle gch;
|
||||
internal sealed class NSAsyncActionDispatcher : NSAsyncDispatcher {
|
||||
Action action;
|
||||
|
||||
public NSAsyncActionDispatcher (Action action)
|
||||
{
|
||||
if (action == null)
|
||||
throw new ArgumentNullException (nameof (action));
|
||||
|
||||
this.action = action;
|
||||
gch = GCHandle.Alloc (this);
|
||||
IsDirectBinding = false;
|
||||
}
|
||||
|
||||
[Export (NSActionDispatcher.SelectorName)]
|
||||
[Preserve (Conditional = true)]
|
||||
public void Apply ()
|
||||
public override void Apply ()
|
||||
{
|
||||
try {
|
||||
action ();
|
||||
} finally {
|
||||
action = null; // this is a one-shot dispatcher
|
||||
gch.Free ();
|
||||
action = null;
|
||||
base.Apply ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Although I would like to call Dispose here, to
|
||||
// reduce the load on the GC, we have some useful diagnostic
|
||||
// code in our runtime that is useful to track down
|
||||
// problems, so we are removing the Dispose and letting
|
||||
// the GC and our pipeline do their job.
|
||||
//
|
||||
#if MONOTOUCH
|
||||
// MonoTouch has fixed the above problems, and we can call
|
||||
// Dispose here.
|
||||
Dispose ();
|
||||
#endif
|
||||
// Use this for asynchronous operations
|
||||
[Register ("__MonoMac_NSAsyncSynchronizationContextDispatcher")]
|
||||
internal sealed class NSAsyncSynchronizationContextDispatcher : NSAsyncDispatcher {
|
||||
SendOrPostCallback d;
|
||||
object state;
|
||||
|
||||
public NSAsyncSynchronizationContextDispatcher (SendOrPostCallback d, object state)
|
||||
{
|
||||
if (d == null)
|
||||
throw new ArgumentNullException (nameof (d));
|
||||
|
||||
this.d = d;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public override void Apply ()
|
||||
{
|
||||
try {
|
||||
d (state);
|
||||
} finally {
|
||||
d = null; // this is a one-shot dispatcher
|
||||
state = null;
|
||||
base.Apply ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -576,10 +576,22 @@ namespace Foundation {
|
|||
var d = new NSAsyncActionDispatcher (action);
|
||||
#if MONOMAC
|
||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle,
|
||||
NSActionDispatcher.Selector.Handle, d.Handle, false);
|
||||
NSDispatcher.Selector.Handle, d.Handle, false);
|
||||
#else
|
||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.GetHandle (Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDone),
|
||||
Selector.GetHandle (NSActionDispatcher.SelectorName), d.Handle, false);
|
||||
Selector.GetHandle (NSDispatcher.SelectorName), d.Handle, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal void BeginInvokeOnMainThread (System.Threading.SendOrPostCallback cb, object state)
|
||||
{
|
||||
var d = new NSAsyncSynchronizationContextDispatcher (cb, state);
|
||||
#if MONOMAC
|
||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle,
|
||||
NSDispatcher.Selector.Handle, d.Handle, false);
|
||||
#else
|
||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.GetHandle (Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDone),
|
||||
Selector.GetHandle (NSDispatcher.SelectorName), d.Handle, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -588,14 +600,27 @@ namespace Foundation {
|
|||
using (var d = new NSActionDispatcher (action)) {
|
||||
#if MONOMAC
|
||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle,
|
||||
NSActionDispatcher.Selector.Handle, d.Handle, true);
|
||||
NSDispatcher.Selector.Handle, d.Handle, true);
|
||||
#else
|
||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.GetHandle (Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDone),
|
||||
Selector.GetHandle (NSActionDispatcher.SelectorName), d.Handle, true);
|
||||
Selector.GetHandle (NSDispatcher.SelectorName), d.Handle, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
internal void InvokeOnMainThread (System.Threading.SendOrPostCallback cb, object state)
|
||||
{
|
||||
using (var d = new NSSynchronizationContextDispatcher (cb, state)) {
|
||||
#if MONOMAC
|
||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle,
|
||||
NSDispatcher.Selector.Handle, d.Handle, true);
|
||||
#else
|
||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.GetHandle (Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDone),
|
||||
Selector.GetHandle (NSDispatcher.SelectorName), d.Handle, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static NSObject FromObject (object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
|
@ -739,13 +764,13 @@ namespace Foundation {
|
|||
public virtual void Invoke (Action action, double delay)
|
||||
{
|
||||
var d = new NSAsyncActionDispatcher (action);
|
||||
d.PerformSelector (NSActionDispatcher.Selector, null, delay);
|
||||
d.PerformSelector (NSDispatcher.Selector, null, delay);
|
||||
}
|
||||
|
||||
public virtual void Invoke (Action action, TimeSpan delay)
|
||||
{
|
||||
var d = new NSAsyncActionDispatcher (action);
|
||||
d.PerformSelector (NSActionDispatcher.Selector, null, delay.TotalSeconds);
|
||||
d.PerformSelector (NSDispatcher.Selector, null, delay.TotalSeconds);
|
||||
}
|
||||
|
||||
internal void ClearHandle ()
|
||||
|
|
|
@ -21,12 +21,12 @@ namespace UIKit {
|
|||
|
||||
public override void Post (SendOrPostCallback d, object state)
|
||||
{
|
||||
NSRunLoop.Main.BeginInvokeOnMainThread ( () => d (state) );
|
||||
NSRunLoop.Main.BeginInvokeOnMainThread (d, state);
|
||||
}
|
||||
|
||||
public override void Send (SendOrPostCallback d, object state)
|
||||
{
|
||||
NSRunLoop.Main.InvokeOnMainThread ( () => d (state) );
|
||||
NSRunLoop.Main.InvokeOnMainThread (d, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче