如何使用MonoTouch.ObjCRuntime.Selector和Perform Selector发送参数

时间:2012-05-07 00:21:47

标签: c# iphone ios xamarin.ios monodevelop

这是我发现的一个例子,但他们实际上省略了发送参数。

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 Call以将params发送到方法?

2 个答案:

答案 0 :(得分: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#lambda安全地捕获参数。

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

答案 1 :(得分: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);
            }
        }
    }
}