带范围的 pyobjc 索引访问器方法

发布于 2024-08-04 08:53:24 字数 1037 浏览 6 评论 0原文

我正在尝试在 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]

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

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

但这似乎也不起作用。第一个参数应该是指向 C 数组的指针,但长度在运行时之前是未知的,因此我不知道如何构造正确的类型编码。我尝试了 'v@:N^[1000@]@' 只是为了看看,但这也不起作用。

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

I'm trying to implement an indexed accessor method for my model class in Python, as per the KVC guide. I want to use the optional ranged method, to load multiple objects at once for performance reasons. The method takes a pointer to a C-array buffer which my method needs to copy the objects into. I've tried something like the following, which doesn't work. How do I accomplish this?

@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]

Edit: I finally found the type encodings reference after Apple moved all the docs. After reading that, I tried this:

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

but this didn't appear to work either. The first argument is supposed to be a pointer to a C-array, but the length is unknown until runtime, so I didn't know exactly how to construct the correct type encoding. I tried 'v@:N^[1000@]@' just to see, and that didn't work either.

My model object is bound to the contentArray of an NSArrayController driving a table view. It doesn't appear to be calling this method at all, perhaps because it expects a different signature than the one the bridge is providing. Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鹿港小镇 2024-08-11 08:53:24

你很接近。该方法正确的装饰器是:

@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}')
             }
        )
)

可以在文件 test_metadata_py.py(以及 PyObjC 源中附近的 test_metadata*.py 文件)。

注意,元数据必须在您有兴趣实现 get:range: 的任何类的超类上指定,并且另外,这个函数需要在类定义结束之前调用(但在 class 语句本身之前或内部似乎都可以工作)。我也还没有弄清楚这些。

我将此元数据基于 Foundation PyObjC.bridgesupport 文件2NSArray getObjects:range: 的元数据,并通过参考 Apple 的 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 ints
2:位于(在雪豹上):/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/PyObjC/Foundation/PyObjC.bridgesupport

You were close. The correct decorator for this method is:

@objc.signature('v@:o^@{_NSRange=QQ}')

NSRange is not an object, but a struct, and can't be specified simply as @; you need to include the members1.

Unfortunately, this is not the end of it. After a whole lot of experimentation and poring over the PyObjC source, I finally figured out that in order to get this method to work, you also need to specify metadata for the method that is redundant to this signature. (However, I still haven't puzzled out why.)

This is done using the function 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}')
             }
        )
)

Examples and some details of the use of this function can be found in the file test_metadata_py.py (and nearby test_metadata*.py files) in the PyObjC source.

N.B. that the metadata has to be specified on the superclass of whatever class you are interested in implementing get<Key>:range: for, and also that this function needs to be called sometime before the end of your class definition (but either before or inside the class statement itself both seem to work). I haven't yet puzzled these bits out either.

I based this metadata on the metadata for NSArray getObjects:range: in the Foundation PyObjC.bridgesupport file2, and was aided by referring to Apple's BridgeSupport manpage.

With this worked out, it's also worth noting that the easiest way to define the method is (at least, 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)

I.e., using your array's built-in getObjects:range:.


1: On 32-bit Python, the QQ, meaning two unsigned long longs, should become II, meaning two unsigned ints
2: Located (on Snow Leopard) at: /System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/PyObjC/Foundation/PyObjC.bridgesupport

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文