Можно ли передать делегат в качестве параметра другого делегата в проекте bindings?
Я пытаюсь заставить работать проект привязки. Но я столкнулся с ошибкой, когда мне не нравится передавать делегата в качестве параметра другому делегату.
Ошибка, которую я получаю, заключается в следующем;
"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, то библиотека привязок не будет компилироваться.
Мой файл 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. Но мои push-уведомления работают нормально и все в порядке.
Поэтому я просто пытаюсь найти способ вызвать этот обратный вызов без сбоев. Кажется, что когда Xamarin генерирует код привязки, у него возникает много проблем с выбором типа второго делегата.
Если я использую NotificatioNHandler как это;
public delegate void NotificationHandler(NSDictionary info, Action<UIBackgroundFetchResult> action);
Библиотека привязок не скомпилируется, и я получаю сообщение об ошибке о недопустимом символе "Action`1"
Есть ли кто-нибудь может придумать, чтобы это заработало. Заранее спасибо!
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);