如何将python callable作为“block”类型的参数传递给objc方法

时间:2012-07-17 23:01:29

标签: python objective-c pyobjc

我有像这样的objc方法;

@ implementation of Class1

- (void)execute:(void (^)(Class2* target, NSUInteger idx))block
{
... 

}

我想在python中使用这个execute方法,我已经构建了一个python objective-c桥接数据,它似乎正确地生成为:

<class name='Class1'>
<method selector='execute:'>
<arg function_pointer='true' type='@?' index='0'>
    <arg type='@'/>
    <arg type='I' type64='Q'/>
    <retval type='v'/>
</arg>
</method>

但是当我定义这样的函数时:

def myFunc (dev, index):
    // do something with dev
    print("Hello")

并尝试将其用作块

class1_obj.execute_(myFunc)

Python将错误抛出为:

objc.BadPrototypeError: Objective-C expects 1 arguments, Python argument has 2 arguments for <unbound selector myFunc at 0x105b3a3f0>

我也试过lambda函数,没用。

我还尝试创建一个可调用的类:

>>> class myCallable(object):
...     def __init__(self,name):
...             print "Init"
...     def __repr__(self):
...             return "string init"
...     def __call__(self, dev, index):
...             # do something with dev
...             print("hello")

但是python会抛出这样的错误:

TypeError: Sorry, cannot create IMP for instances of type myCallable

我想知道我在哪里做错了?

1 个答案:

答案 0 :(得分:2)

感谢Josh的建议。

终于解决了这个问题。看起来系统使用命令行gen_bridge_metadata生成的meta_data无法正确读取。它生成为:

<method selector='execute:'>
<arg index='0' type='@?' function_pointer='true'>
<arg type='@'/>
<arg type64='Q' type='I'/>
<retval type='v'/>
</arg>
</method>

但是在我将function_pointer更改为block后,它可以工作。我通过阅读pyobjc单元测试来获得这个块。

<method selector='execute:'>
<arg index='0' type='@?' block='true'>
<arg type='@'/>
<arg type64='Q' type='I'/>
<retval type='v'/>
</arg>
</method>

我不确定是什么原因引起的。 Apple Doc说如果type =“@?”和function_pointer ='true',它被视为块。如果type =“#?”和function_pointer =“true”,它将被解释为function_pointer。但为什么pyobjc无法识别这个?这是pyobjc中的一个错误吗?