Можно ли передать делегата в качестве параметра другого делегата в проекте привязок

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

Ошибка, которую я получаю, заключается в следующем;

"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);

Все работает нормально, за исключением того факта, что я не могу вызвать обратный вызов, потому что это int. Но мои push-уведомления работают нормально и все в порядке.

Итак, я просто пытаюсь найти способ вызвать этот обратный вызов без сбоя. Похоже, что когда Xamarin генерирует код привязки, у него возникают проблемы с принятием решения о том, какой тип должен быть вторым делегатом.

Если я использую NotificatioNHandler как это;

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

Библиотека привязок не компилируется, и я получаю сообщение об ошибке о недопустимом символе "Action`1"

Есть ли вообще кто-нибудь может придумать, чтобы это работало. Заранее спасибо!


person Derek Lawrence    schedule 25.04.2017    source источник


Ответы (1)


Хорошо, в итоге я посмотрел на скомпилированный код в папке 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);
person Derek Lawrence    schedule 26.04.2017