是否可以在委托项目

时间:2017-04-25 00:06:03

标签: xamarin xamarin.ios delegates xamarin-binding

我正在尝试让绑定项目正常运行。但是我遇到了一个错误,它不喜欢我将委托作为参数传递给另一个委托。

我收到的错误是这个;

"Attempting to JIT compile method '(wrapper runtime-invoke) 
:BackgroundFetchResultHandler(object,UIBackgroundFetchResult)' while running 
with --aot-only.

有关详细信息,请参阅http://docs.xamarin.com/ios/about/limitations。\ n“

所以正在发生的事情是我正在使用PushySDK并创建了一个绑定库项目。绑定项目中的所有内容都起作用,但BackgroundFetchResultHandler委托除外。如果我尝试使用动作或Func而不是BackgroundFetchResultHandler的委托,则绑定lib将不会编译。

我的apiDefinitions.cs文件就是这个;

using System;
using Foundation;
using UIKit;

namespace PushySDK
{
    public delegate void BackgroundFetchResultHandler(UIBackgroundFetchResult result);
    public delegate void NotificationHandler(NSDictionary info, BackgroundFetchResultHandler action);

    // @interface Pushy : NSObject
    [BaseType(typeof(NSObject), Name = "_TtC8PushySDK5Pushy")]
    [DisableDefaultCtor]
    interface Pushy
    {
        // -(instancetype _Nonnull)init:(UIResponder * _Nonnull)appDelegate application:(UIApplication * _Nonnull)application __attribute__((objc_designated_initializer));
        [Export("init:application:")]
        [DesignatedInitializer]
        IntPtr Constructor(UIResponder appDelegate, UIApplication application);

        // -(void)setNotificationHandler:(void (^ _Nonnull)(NSDictionary * _Nonnull, void (^ _Nonnull)(UIBackgroundFetchResult)))notificationHandler;
        [Export("setNotificationHandler:")] 
        void SetNotificationHandler(NotificationHandler notificationHandler);

        // -(void)register:(void (^ _Nonnull)(NSError * _Nullable, NSString * _Nonnull))registrationHandler;
        [Export("register:")]
        void Register(Action<NSError, NSString> registrationHandler);
    }
}

我试图使用操作而不是委托,但我得到了同样的错误。如果我将NotificationHandler委托更改为;

public delegate void NotificationHandler(NSDictionary info, int action);

Everythign工作正常,除了我无法调用回调因为它是一个int。但我的推送通知工作正常,一切都很好。

所以我只是想找到一种方法来调用这个回调而不会崩溃。看起来当Xamarin生成绑定代码时,决定第二个委托应该是什么类型时会遇到很多麻烦。

如果我使用NotificatioNHandler;

public delegate void NotificationHandler(NSDictionary info, Action<UIBackgroundFetchResult> action);

绑定库不会编译,我收到有关无效字符“Action`1”的错误

无论如何,任何人都可以想到让这个工作。提前谢谢!

1 个答案:

答案 0 :(得分:0)

好的,所以我最终查看了obj文件夹中的编译代码,看看他们是如何做第一个代理的。所以我只是将它复制为委托类型,将其更改为IntPtr。我的api定义文件就像这样结束了。

using System;
using Foundation;
using UIKit;
using ObjCRuntime;

namespace PushySDK
{
internal delegate void NotificationHandler(NSDictionary info, IntPtr action);

// @interface Pushy : NSObject
[BaseType(typeof(NSObject), Name = "_TtC8PushySDK5Pushy")]
[DisableDefaultCtor]
interface Pushy
{
    // -(instancetype _Nonnull)init:(UIResponder * _Nonnull)appDelegate application:(UIApplication * _Nonnull)application __attribute__((objc_designated_initializer));
    [Export("init:application:")]
    [DesignatedInitializer]
    IntPtr Constructor(UIResponder appDelegate, UIApplication application);

    // -(void)setNotificationHandler:(void (^ _Nonnull)(NSDictionary * _Nonnull, void (^ _Nonnull)(UIBackgroundFetchResult)))notificationHandler;
    [Export("setNotificationHandler:")]
    void SetNotificationHandler(NotificationHandler notificationHandler);

    // -(void)register:(void (^ _Nonnull)(NSError * _Nullable, NSString * _Nonnull))registrationHandler;
    [Export("register:")]
    void Register(Action<NSError, NSString> registrationHandler);
}
}

我在APPDelegate类中声明了将分配回调的委托。

[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
internal delegate void DBackgroundFetchResultHandler(IntPtr blockPtr, nuint result); 

在appDelegate中声明这个内部类

internal class BackgroundFetchResultHandlerProxy
    {
        IntPtr blockPtr;
        DBackgroundFetchResultHandler invoker;

        [Preserve(Conditional = true)]
        public unsafe BackgroundFetchResultHandlerProxy(BlockLiteral* block)
        {
            blockPtr = _Block_copy((IntPtr)block);
            invoker = block->GetDelegateForBlock<DBackgroundFetchResultHandler>();
        }

        [Preserve(Conditional = true)]
        ~BackgroundFetchResultHandlerProxy()
        {
            _Block_release(blockPtr);
        }

        [Preserve(Conditional = true)]
        internal unsafe void Invoke(UIBackgroundFetchResult result)
        {
            invoker(blockPtr, (nuint) (UInt64) result);
        }
    }

然后我将我的功能改为

[Export("handleNotification:completionHandler:")]
internal unsafe void HandleNotification(NSDictionary info, IntPtr actionPtr)
{
    var proxy = new BackgroundFetchResultHandlerProxy((BlockLiteral *)actionPtr);
        proxy.Invoke(UIBackgroundFetchResult.NewData);
}

然后我就可以打电话了

pushy.SetNotificationHandler(HandleNotification);