pyobjc 索引访问器方法与范围

3 投票
1 回答
547 浏览
提问于 2025-04-15 14:03

我正在尝试为我的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 个回答

2

你离答案很近。这个方法的正确装饰器是:

@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

撰写回答