pyobjc 索引访问器方法与范围
我正在尝试为我的Python模型类实现一个索引访问方法,参考了KVC指南。我想使用可选的范围方法,一次加载多个对象以提高性能。这个方法需要一个指向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]
编辑:我终于找到了类型编码参考,因为苹果把所有文档都移动了。看完之后,我尝试了这个:
@objc.signature('v@:N^@@')
def getFoos_range_(self, buf, range):
但这似乎也不行。第一个参数应该是指向C语言数组的指针,但长度在运行时才知道,所以我不知道该如何构造正确的类型编码。我试了'v@:N^[1000@]@'
,只是想看看,但也没有成功。
我的模型对象绑定到了一个控制器的contentArray上,这个控制器驱动着一个表格视图。似乎根本没有调用这个方法,可能是因为它期望的签名和桥接提供的不同。有没有什么建议呢?
1 个回答
你离答案很近。这个方法的正确装饰器是:
@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>:range:
的类的 父类 上指定,并且这个函数需要在你的类定义结束之前的某个时刻被调用(但在 class
语句之前或内部调用似乎都可以)。我还没有搞清楚这些细节。
我是根据 Foundation PyObjC.bridgesupport 文件中 NSArray getObjects:range:
的元数据来构建这个元数据的2,并参考了苹果的 BridgeSupport 手册。
搞定这些之后,值得注意的是,定义这个方法的最简单方式是(至少在我看来):
@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
,表示两个 unsigned long long
,应该变成 II
,表示两个 unsigned int
2: 在 Snow Leopard 系统中,位置在:/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/PyObjC/Foundation/PyObjC.bridgesupport