3

根据 KVC 指南,我正在尝试在 Python 中为我的模型类实现索引访问器方法。出于性能原因,我想使用可选的 ranged 方法一次加载多个对象。该方法需要一个指向 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]

编辑: Apple 移动所有文档后,我终于找到了类型编码参考。读完之后,我尝试了这个:

@objc.signature('v@:N^@@')
def getFoos_range_(self, buf, range):

但这似乎也不起作用。第一个参数应该是指向 C 数组的指针,但长度直到运行时才知道,所以我不知道如何构造正确的类型编码。我'v@:N^[1000@]@'只是想看看,那也没用。

我的模型对象绑定到驱动表视图的 NSArrayController 的 contentArray。它似乎根本没有调用此方法,可能是因为它期望的签名与桥提供的签名不同。有什么建议么?

4

1 回答 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语句本身之前或内部似乎都工作)。我还没有弄明白这些位。

我将此元数据基于NSArray getObjects:range:Foundation PyObjC.bridgesupport 文件2中的元数据,并参考了 Apple 的BridgeSupport 手册页

解决了这个问题,还值得注意的是,定义该方法的最简单方法是(至少,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,表示两个sunsigned long long的 应该变为II,表示两个 2:位于(在 Snow Leopard 上):/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python /PyObjC/Foundation/PyObjC.bridgesupportunsigned int

于 2011-03-17T08:54:04.907 回答