我正在尝试按照the KVC guide在Python中为我的模型类实现索引访问器方法.出于性能原因,我想使用可选的ranged方法来一次加载多个对象.该方法使用一个指向C数组缓冲区的指针,我的方法需要将该对象复制到C数组缓冲区中.我已经尝试过类似以下的方法,但无法正常工作.我该如何完成?
@objc.accessor # i've also tried @objc.signature('v@:o^@')
def getFoos_range_(self, range):
return self._some_array[range.location:range.location + range.length]
编辑:苹果移动了所有文档之后,我终于找到了type encodings reference.看完之后,我尝试了一下:
@objc.signature('v@:N^@@')
def getFoos_range_(self, buf, range):
但这似乎也不起作用.第一个参数应该是指向C数组的指针,但是长度在运行时之前是未知的,所以我不知道如何构造正确的类型编码.我试过’v @:N ^ [1000 @] @’只是想看看,但是那也不起作用.
我的模型对象绑定到驱动表视图的NSArrayController的contentArray上.它似乎根本没有调用此方法,可能是因为它期望与网桥提供的签名不同的签名.有什么建议么?
解决方法:
你近了此方法的正确装饰器是:
@objc.signature('v@:o^@{_NSRange=QQ}')
NSRange不是对象,而是结构,不能简单地指定为@;您需要包括成员1.
不幸的是,这还没有结束.经过大量的实验和对PyObjC源代码的研究,我终于弄清楚了,为了使此方法起作用,您还需要为该签名指定多余的元数据. (但是,我仍然不知道为什么.)
这可以通过使用objc.registerMetaDataForSelector函数来完成:
objc.registerMetaDataForSelector(b"SUPERCLASSNAME",
b"getKey:range:",
dict(retval=dict(type=objc._C_VOID),
arguments={
2+0: dict(type_modifier=objc._C_OUT,
c_array_length_in_arg=2+1),
2+1: dict(type=b'{_NSRange=II}',
type64=b'{_NSRange=QQ}')
}
)
)
在PyObjC源代码的文件test_metadata_py.py
(和附近的test_metadata * .py文件)中可以找到使用此功能的示例和一些详细信息.
注:必须在要实现get< Key:gt:range:for的任何类的超类上指定元数据,并且还需要在类定义结束之前的某个时候调用此函数(但必须在类定义之前或内部)类语句本身似乎都可以工作).我也没有弄清楚这些内容. 我将此元数据基于Foundation PyObjC.bridgesupport文件2中NSArray getObjects:range:的元数据,并通过参考Apple的BridgeSupport manpage得到了帮助.
有了这个解决方案,还值得注意的是定义该方法的最简单方法是(至少是IMO):
@objc.signature('v@:o^@{_NSRange=QQ}')
def get<#Key#>_range_(self, buf, inRange):
#NSLog(u"get<#Key#>")
return self.<#Key#>.getObjects_range_(buf, inRange)
即,使用数组的内置getObjects:range:.
1:在32位Python上,QQ(意味着两个无符号的long long)应该变成II,意味着两个无符号的int
2 :(在Snow Leopard上)位于:/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/PyObjC/Foundation/PyObjC.bridgesupport