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)
|
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)
|
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;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
using ObjCRuntime;
|
using ObjCRuntime;
|
||||||
|
|
||||||
namespace Foundation {
|
namespace Foundation {
|
||||||
|
|
||||||
#if !COREBUILD
|
#if !COREBUILD
|
||||||
// Use this for synchronous operations
|
// Use this for synchronous operations
|
||||||
[Register ("__MonoMac_NSActionDispatcher")]
|
internal abstract class NSDispatcher : NSObject
|
||||||
internal sealed class NSActionDispatcher : NSObject {
|
{
|
||||||
public const string SelectorName = "xamarinApplySelector";
|
public const string SelectorName = "xamarinApplySelector";
|
||||||
public static readonly Selector Selector = new Selector (SelectorName);
|
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;
|
readonly Action action;
|
||||||
|
|
||||||
public NSActionDispatcher (Action action)
|
public NSActionDispatcher (Action action)
|
||||||
|
@ -43,40 +57,28 @@ namespace Foundation {
|
||||||
throw new ArgumentNullException ("action");
|
throw new ArgumentNullException ("action");
|
||||||
|
|
||||||
this.action = action;
|
this.action = action;
|
||||||
IsDirectBinding = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Export (SelectorName)]
|
public override void Apply () => action ();
|
||||||
[Preserve (Conditional = true)]
|
|
||||||
public void Apply ()
|
|
||||||
{
|
|
||||||
action ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this for synchronous operations
|
// Use this for synchronous operations
|
||||||
[Register ("__MonoMac_ActionDispatcher")]
|
[Register ("__MonoMac_NSSynchronizationContextDispatcher")]
|
||||||
internal sealed class ActionDispatcher : NSObject {
|
internal sealed class NSSynchronizationContextDispatcher : NSDispatcher
|
||||||
public const string SelectorName = "xamarinApplySelector";
|
{
|
||||||
public static readonly Selector Selector = new Selector (SelectorName);
|
readonly SendOrPostCallback d;
|
||||||
|
readonly object state;
|
||||||
|
|
||||||
readonly Action action;
|
public NSSynchronizationContextDispatcher (SendOrPostCallback d, object state)
|
||||||
|
|
||||||
public ActionDispatcher (Action action)
|
|
||||||
{
|
{
|
||||||
if (action == null)
|
if (d == null)
|
||||||
throw new ArgumentNullException ("action");
|
throw new ArgumentNullException (nameof (d));
|
||||||
|
|
||||||
this.action = action;
|
this.d = d;
|
||||||
IsDirectBinding = false;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Export (SelectorName)]
|
public override void Apply () => d (state);
|
||||||
[Preserve (Conditional = true)]
|
|
||||||
public void Apply ()
|
|
||||||
{
|
|
||||||
action ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used this for NSTimer support
|
// 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
|
// Use this for asynchronous operations
|
||||||
[Register ("__MonoMac_NSAsyncActionDispatcher")]
|
[Register ("__MonoMac_NSAsyncActionDispatcher")]
|
||||||
internal class NSAsyncActionDispatcher : NSObject {
|
internal sealed class NSAsyncActionDispatcher : NSAsyncDispatcher {
|
||||||
GCHandle gch;
|
|
||||||
Action action;
|
Action action;
|
||||||
|
|
||||||
public NSAsyncActionDispatcher (Action action)
|
public NSAsyncActionDispatcher (Action action)
|
||||||
{
|
{
|
||||||
|
if (action == null)
|
||||||
|
throw new ArgumentNullException (nameof (action));
|
||||||
|
|
||||||
this.action = action;
|
this.action = action;
|
||||||
gch = GCHandle.Alloc (this);
|
|
||||||
IsDirectBinding = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Export (NSActionDispatcher.SelectorName)]
|
public override void Apply ()
|
||||||
[Preserve (Conditional = true)]
|
|
||||||
public void Apply ()
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
action ();
|
action ();
|
||||||
} finally {
|
} finally {
|
||||||
action = null; // this is a one-shot dispatcher
|
action = null;
|
||||||
gch.Free ();
|
base.Apply ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
// Use this for asynchronous operations
|
||||||
// Although I would like to call Dispose here, to
|
[Register ("__MonoMac_NSAsyncSynchronizationContextDispatcher")]
|
||||||
// reduce the load on the GC, we have some useful diagnostic
|
internal sealed class NSAsyncSynchronizationContextDispatcher : NSAsyncDispatcher {
|
||||||
// code in our runtime that is useful to track down
|
SendOrPostCallback d;
|
||||||
// problems, so we are removing the Dispose and letting
|
object state;
|
||||||
// the GC and our pipeline do their job.
|
|
||||||
//
|
public NSAsyncSynchronizationContextDispatcher (SendOrPostCallback d, object state)
|
||||||
#if MONOTOUCH
|
{
|
||||||
// MonoTouch has fixed the above problems, and we can call
|
if (d == null)
|
||||||
// Dispose here.
|
throw new ArgumentNullException (nameof (d));
|
||||||
Dispose ();
|
|
||||||
#endif
|
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);
|
var d = new NSAsyncActionDispatcher (action);
|
||||||
#if MONOMAC
|
#if MONOMAC
|
||||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle,
|
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle,
|
||||||
NSActionDispatcher.Selector.Handle, d.Handle, false);
|
NSDispatcher.Selector.Handle, d.Handle, false);
|
||||||
#else
|
#else
|
||||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.GetHandle (Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDone),
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,14 +600,27 @@ namespace Foundation {
|
||||||
using (var d = new NSActionDispatcher (action)) {
|
using (var d = new NSActionDispatcher (action)) {
|
||||||
#if MONOMAC
|
#if MONOMAC
|
||||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle,
|
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle,
|
||||||
NSActionDispatcher.Selector.Handle, d.Handle, true);
|
NSDispatcher.Selector.Handle, d.Handle, true);
|
||||||
#else
|
#else
|
||||||
Messaging.void_objc_msgSend_IntPtr_IntPtr_bool (d.Handle, Selector.GetHandle (Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDone),
|
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
|
#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)
|
public static NSObject FromObject (object obj)
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
|
@ -739,13 +764,13 @@ namespace Foundation {
|
||||||
public virtual void Invoke (Action action, double delay)
|
public virtual void Invoke (Action action, double delay)
|
||||||
{
|
{
|
||||||
var d = new NSAsyncActionDispatcher (action);
|
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)
|
public virtual void Invoke (Action action, TimeSpan delay)
|
||||||
{
|
{
|
||||||
var d = new NSAsyncActionDispatcher (action);
|
var d = new NSAsyncActionDispatcher (action);
|
||||||
d.PerformSelector (NSActionDispatcher.Selector, null, delay.TotalSeconds);
|
d.PerformSelector (NSDispatcher.Selector, null, delay.TotalSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ClearHandle ()
|
internal void ClearHandle ()
|
||||||
|
|
|
@ -21,12 +21,12 @@ namespace UIKit {
|
||||||
|
|
||||||
public override void Post (SendOrPostCallback d, object state)
|
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)
|
public override void Send (SendOrPostCallback d, object state)
|
||||||
{
|
{
|
||||||
NSRunLoop.Main.InvokeOnMainThread ( () => d (state) );
|
NSRunLoop.Main.InvokeOnMainThread (d, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче