7

这是我找到的一个示例,但他们省略了实际发送参数。

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 调用以将参数发送到方法?

4

2 回答 2

9

MonoTouch 文档表明该方法映射到 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));
于 2012-05-07T02:59:11.410 回答
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);
            }
        }
    }
}
于 2012-05-07T02:36:02.877 回答