2012-05-07 5 views
7

Aquí hay un ejemplo que encontré, pero omitieron el envío de los params.Cómo envío parámetros usando MonoTouch.ObjCRuntime.Selector y Perform Selector

this.PerformSelector(new MonoTouch.ObjCRuntime.Selector("_HandleSaveButtonTouchUpInside"),null,0.0f); 

[Export("_HandleSaveButtonTouchUpInside")] 
    void _HandleSaveButtonTouchUpInside() 
    { 
... 
} 

Me gustaría ser capaz de hacer algo como esto:

this.PerformSelector(new MonoTouch.ObjCRuntime.Selector("_HandleSaveButtonTouchUpInside"),null,0.0f); 

[Export("_HandleSaveButtonTouchUpInside")] 
    void _HandleSaveButtonTouchUpInside(NSURL url, NSData data) 
    { 
... 
} 

¿Cómo cambio el PerformSelector llamada para enviar params al método?

Respuesta

9

El MonoTouch docs indican que método asigna al selector Obj-C performSelector:withObject:afterDelay, que sólo admite la invocación de un selector con un solo argumento.

La mejor manera de manejar esto depende de lo que necesite hacer. Una forma típica de manejar esto sería colocar los argumentos como propiedades/campos en un único objeto NSO, luego el objetivo se modificaría para tener un único argumento, y extraer los argumentos reales de ese método. Si hiciera esto con un objeto MonoTouch personalizado, tendría que tener cuidado con el GC que recopila el par administrado, si nada en el código administrado guardara una referencia al mismo.

Una mejor solución dependerá exactamente de cómo la utilice. Por ejemplo, en su ejemplo, puede llamar trivialmente al método C# directamente, p.

_HandleSaveButtonTouchUpInside (url, data); 

Si tiene que enviar a través de Obj-C, por alguna razón, pero no es necesario el retraso, utilice MonoTouch.ObjCRuntime.Messaging, por ejemplo,

MonoTouch.ObjCRuntime.Messaging.void_objc_msgSend_IntPtr_IntPtr (
    target.Handle, 
    MonoTouch.ObjCRuntime.Selector.GetHandle ("_HandleSaveButtonTouchUpInside"), 
    arg0.Handle, 
    arg1.Handle); 

Si necesita el retraso, se puede usar un NSTimer. MonoTouch ha agregado soporte especial para esto para usar un delegado NSAction, por lo que puede usar un lambda C# para capturar argumentos de manera segura.

NSTimer.CreateScheduledTimer (someTimespan,() => _HandleSaveButtonTouchUpInside (url, data)); 
+0

Gracias por la minuciosa respuesta mhutch. He estado usando PerformSelector cuando necesitaba liberar el hilo principal para que Cocoa redibujara la pantalla, y luego pude volver a procesar algo de lógica. En este momento estoy tratando de actualizar el equivalente de una barra de progreso que se ha dibujado en la pantalla durante un writeStream para el ciclo que tengo. Quería ver si esencialmente podía actualizar la pantalla colocando un selector de rendimiento dentro del ciclo for y actualizando la propiedad de la barra de progreso. –

+0

Otra forma de hacerlo sería usar un hilo para la lógica/secuencia, y usar InvokeOnMainThread del hilo para actualizar la UI. –

+0

Esto me salvó de tener que volver a vincular manualmente una biblioteca porque el desarrollador original no enlazó una propiedad en particular, o liberar la fuente, así que gracias. Para cualquier persona interesada, las propiedades se pueden establecer fácilmente usando el método msgSend_IntPtr_IntPtr llamando a setColor: donde color es el nombre de la propiedad. (Arg 0 es el valor de la propiedad, Arg 1 = IntPtr.Zero) – Dermot

4

No pude encontrar el enlace para esta llamada tampoco. En el ejemplo a continuación agregué mi propia sobrecarga para PerformSelector. Tal vez uno de los ingenieros de Xamarin puede confirmar esto.

using System; 
using MonoTouch.Foundation; 
using MonoTouch.UIKit; 
using MonoTouch.ObjCRuntime; 
using System.Runtime.InteropServices; 

namespace delete20120506 
{ 
    [Register ("AppDelegate")] 
    public partial class AppDelegate : UIApplicationDelegate 
    { 
     UIWindow window; 

     public override bool FinishedLaunching (UIApplication app, NSDictionary options) 
     { 
      window = new UIWindow (UIScreen.MainScreen.Bounds); 

      // 
      Target target = new Target(); 
      NSUrl url = new NSUrl ("http://xamarin.com/"); 
      NSData nsData = NSData.FromString ("Hello"); 

      target.PerformSelector (new MonoTouch.ObjCRuntime.Selector 
            ("TestSelUrl:withData:"), url, nsData); 

      window.MakeKeyAndVisible(); 

      return true; 
     } 
    } 

    [Register ("Target")] 
    public class Target : NSObject 
    { 
     public Target() : base (NSObjectFlag.Empty) {} 

     [Export("TestSelUrl:withData:")] 
     void TestSelUrlWithData(NSUrl url, NSData nsData) 
     { 
      Console.WriteLine ("In TestSelUrlWithData"); 
      Console.WriteLine (url.ToString()); 
      Console.WriteLine (nsData.ToString()); 
      return; 
     } 

     [DllImport ("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")] 
     public static extern void void_objc_msgSend_intptr_intptr_intptr (IntPtr receiver, IntPtr selector, IntPtr arg1, IntPtr arg2, IntPtr arg3); 

     [DllImport ("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSendSuper")] 
     public static extern void void_objc_msgSendSuper_intptr_intptr_intptr (IntPtr receiver, IntPtr selector, IntPtr arg1, IntPtr arg2, IntPtr arg3); 


     public virtual void PerformSelector (MonoTouch.ObjCRuntime.Selector sel, 
               NSObject arg1, NSObject arg2) 
     { 
      if (this.IsDirectBinding) 
      { 
       void_objc_msgSend_intptr_intptr_intptr (this.Handle, 
        Selector.GetHandle ("performSelector:withObject:withObject:"), 
        sel.Handle, arg1.Handle, arg2.Handle); 
      } 
      else 
      { 
       void_objc_msgSendSuper_intptr_intptr_intptr (this.SuperHandle, 
        Selector.GetHandle ("performSelector:withObject:withObject:"), sel.Handle, 
        arg1.Handle, arg2.Handle); 
      } 
     } 
    } 
} 
+0

¡Sobrecarga impresionante del Selector Monotouch! Puedo probar este en mi proyecto holmes. Gracias por compartir. Espero que las personas que buscan PerformSelector se topen con esta pregunta. –

Cuestiones relacionadas