没有参数的iOS委托方法难以绑定

Posted

技术标签:

【中文标题】没有参数的iOS委托方法难以绑定【英文标题】:Difficulty binding iOS delegate method without parameters 【发布时间】:2015-07-06 17:40:39 【问题描述】:

为 Xamarin 绑定 ios lib.a 时,出现以下错误:

btouch: The delegate method Device.SomeDeviceDelegate.CaptureComplete needs to take at least one parameter (BI1003)

绑定已生成Objective Sharpie。

namespace Device 
   

    // @protocol SomeDeviceDelegate <NSObject>
    [Protocol, Model, Preserve]
    [BaseType(typeof(NSObject))]
    interface SomeDeviceDelegate
    
        // @optional -(void)CaptureComplete;
        [Export("CaptureComplete")]
        void CaptureComplete();
    

    // @interface SomeDevice : NSObject
    [Protocol, Model, Preserve]
    [BaseType(typeof(NSObject), Delegates = new[]  "WeakDelegate" , Events = new[]  typeof(SomeDeviceDelegate) )]
    interface SomeDevice
    
        [Wrap("WeakDelegate")]
        SomeDeviceDelegate Delegate  get; set; 

        // @property (assign, nonatomic) id<SomeDeviceDelegate> delegate;
        [NullAllowed, Export("delegate", ArgumentSemantic.Assign)]
        SomeDeviceDelegate WeakDelegate  get; set; 
    


注意。我已将名称更改为 SomeDevice 以隐藏硬件/设备名称 (NDA)。

编译器抱怨// @optional -(void)CaptureComplete; 和各自的绑定CaptureComplete() 没有参数并且它至少需要一个。

问:我需要做什么来绑定这个委托?

我已经尝试过Binding Types Reference Guide 并尝试过应用

EventArgs属性 NoDefaultValue属性 DefaultValueFromArgument属性

更新

我误解了 NoDefaultValueDefaultValueFromArgument 属性,它们在委托返回值(例如 bool)时使用,因为返回会干扰事件的 Xamarin 包装。

【问题讨论】:

【参考方案1】:

我找到了解决办法。

注意:这次我没有更改名称,因为它使答案不太清楚。

处理 ObjC 委托的首选方式是将它们公开为事件,例如

// @interface ICBarCodeReader : ICISMPDevice
[DisableDefaultCtor]
[BaseType(typeof(ICISMPDevice), Delegates = new[]  "WeakDelegate" , Events = new[]  typeof(ICBarCodeReaderDelegate) ))]
public interface ICBarCodeReader

    [Wrap("WeakDelegate")]
    ICBarCodeReaderDelegate Delegate  get; set; 

    // @property (assign, nonatomic) id<ICISMPDeviceDelegate,ICBarCodeReaderDelegate> delegate;
    [NullAllowed, Export("delegate", ArgumentSemantic.Assign)]
    ICBarCodeReaderDelegate WeakDelegate  get; set; 

BaseType 的 Delegate 和 Events 参数,生成包装 ICBarCodeReaderDelegate 上的每个方法的代码。

// @protocol ICBarCodeReaderDelegate
[Protocol, Model, Preserve]
[BaseType(typeof(ICISMPDeviceDelegate))]
public interface ICBarCodeReaderDelegate

    // @required -(void)barcodeData:(id)data ofType:(int)type;
    [Abstract]
    [Export("barcodeData:ofType:")]
    [EventArgs("BarcodeData")]
    void BarcodeData(string data, BarCodeSymbologies type);

    // @required -(void)configurationRequest;
    [Abstract]
    [Export("configurationRequest")]
    void ConfigurationRequest();

这允许你在你的项目中做:

public void Init()

    _sharedBarCodeReader.BarcodeData += OnBarcodeData;


private void OnBarcodeData(object sender, BarcodeDataEventArgs e)

    var barcode = Convert.ToString(sender); // this maps to string data
    //BarCodeSymbologies is in BarcodeDataEventArgs

    var handler = BarCodeData;
    if (handler != null)
        handler(this, barcode);

但是,当方法没有参数时,这种方法会失败,如 btouch 错误消息所示。

我发现的另一种方法(现在看起来简单明了)不是将委托包装为事件,例如

// @interface ICBarCodeReader : ICISMPDevice
[DisableDefaultCtor]
[BaseType(typeof(ICISMPDevice))]
public interface ICBarCodeReader

    [Wrap("WeakDelegate")]
    ICBarCodeReaderDelegate Delegate  get; set; 

    // @property (assign, nonatomic) id<ICISMPDeviceDelegate,ICBarCodeReaderDelegate> delegate;
    [NullAllowed, Export("delegate", ArgumentSemantic.Assign)]
    ICBarCodeReaderDelegate WeakDelegate  get; set; 

并改为创建 Delegate 接口的实现。

例如

public void Init()

    _sharedBarCodeReader.Delegate = new BarCodeReaderDelegate(this);


private class BarCodeReaderDelegate : ICBarCodeReaderDelegate

    public BarCodeReaderDelegate(BarCodeScanner barCodeScanner)
    
        _barCodeScanner = barCodeScanner;
    

    public override void BarcodeData(string data, BarCodeSymbologies type)
    
        var handler = _barCodeScanner.BarCodeData;
        if (handler != null)
            handler(this, data);
    

    public override void ConfigurationRequest()  

    private readonly BarCodeScanner _barCodeScanner;

【讨论】:

【参考方案2】:

“CaptureComplete:”可能正在等待发件人?

【讨论】:

这就是我的想法,但是 ObjC 签名并不表明它确实如此。我尝试向托管方法添加一个参数,但随后又产生了另一个 registrar found a signature mismatch in the method 错误。 我已将: 添加到[Export()],现在可以编译了。 这很遗憾在运行时失败,ObjCRuntime.RuntimeException: Wrapper type 'Device.SomeDeviceDelegate' is missing its native ObjectiveC class 'SomeDeviceDelegate'. 这不是解决方案。

以上是关于没有参数的iOS委托方法难以绑定的主要内容,如果未能解决你的问题,请参考以下文章

jQuery 的事件绑定和事件委托(事件代理)

使用委托从iOS中的ViewModel传递数据到UI的任何替代方法?

[ 面试没回答上的问题2]IOS上给body绑定click事件的bug

Xamarin:绑定 ios 协议/委托无法访问 structs.cs 中定义的枚举

Jquery 在ios上事件委托失效

part01.03 委托与 Lambda 表达式:委托