2012-05-07 2 views
7

Вот пример, который я нашел, но они вообще не указали отправку параметров.Как отправить параметры с помощью MonoTouch.ObjCRuntime.Selector and Perform Selector

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

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

Я хотел бы быть в состоянии сделать что-то вроде этого:

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

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

Как изменить PerformSelector вызов, чтобы отправить Params методу?

ответ

9

MonoTouch docs показывает, что метод карта на селектор Obj-C performSelector:withObject:afterDelay, который поддерживает только ссылающийся селектор с одним аргументом.

Лучший способ справиться с этим зависит от того, что вам нужно делать. Одним из типичных способов справиться с этим было бы поставить аргументы как свойства/поля в одном NSObject, тогда цель будет изменена, чтобы иметь один аргумент, и вытащить реальные аргументы из этого метода. Если вы сделали это с помощью специального объекта MonoTouch, вам нужно будет следить за тем, чтобы GC собирал управляемый одноранговый узел, если ничто в управляемом коде не содержало ссылки на него.

Лучшее решение будет зависеть от того, как вы его используете. Например, в вашем примере вы можете тривиально вызвать метод C# напрямую, например.

_HandleSaveButtonTouchUpInside (url, data); 

Если вам нужно послать через Obj-C по какой-то причине, но не нужна задержка, использовать MonoTouch.ObjCRuntime.Messaging, например,

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

Если вам нужна задержка, вы могли бы использовать NSTimer. MonoTouch добавила специальную поддержку для использования делегата NSAction, поэтому вы можете использовать C# лямбда для безопасного хранения аргументов.

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

Благодарим вас за подробный ответ mhutch. Я использовал PerformSelector, когда мне нужно было освободить основной поток, чтобы какао перерисовал экран, а затем я смог вернуться к обработке некоторой логики. Прямо сейчас я пытаюсь обновить эквивалент строки выполнения, которая была нарисована на экране во время цикла writeStream, который у меня есть. Хотел посмотреть, смогу ли я существенно обновить экран, поставив селектор выполнения в цикле for и обновив свойство индикатора выполнения. –

+0

Другой способ сделать это - использовать поток для логики/потока и использовать InvokeOnMainThread из потока для обновления пользовательского интерфейса. –

+0

Это избавило меня от необходимости вручную переписывать библиотеку, потому что первоначальный разработчик не связывал определенное свойство или не выпускал источник, поэтому спасибо. Для всех желающих свойства можно легко установить с помощью метода msgSend_IntPtr_IntPtr, вызвав setColor: где color - это имя свойства. (Arg 0 - значение свойства, Arg 1 = IntPtr.Zero) – Dermot

4

Я также не смог найти привязку для этого вызова. В приведенном ниже примере я добавил свою собственную перегрузку для PerformSelector. Возможно, один из инженеров Xamarin может подтвердить это.

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

Удивительная перегрузка переключателя Monotouch! Я могу попробовать это в своем проекте holmes. Спасибо, что поделились. Я надеюсь, что люди, которые ищут PerformSelector, попадут на этот вопрос. –

Смежные вопросы