pyobjc索引访问器方法与范围 [英] pyobjc indexed accessor method with range

查看:79
本文介绍了pyobjc索引访问器方法与范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在Python中为我的模型类实现一个索引访问器方法,如 KVC指南。我想使用可选的远程方法,为了性能原因一次加载多个对象。该方法接受一个指向C阵列缓冲区的指针,我的方法需要该指针将对象复制到其中。我试过像下面的东西,这不工作。如何实现这个?

  @ objc.accessor#我也试过@ 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 @] @'只是看到,也没有工作。



我的模型对象绑定到驱动表视图的NSArrayController的contentArray。它似乎根本不是调用这个方法,也许是因为它期望一个不同的签名,而不是桥提供的。有任何建议吗?

解决方案

此方法的正确装饰是:

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

NSRange 不是一个对象,一个结构体,不能简单地指定为 @ ;您需要包括成员 1



不幸的是,这不是结束。在对PyObjC源进行了大量的实验和运算之后,我终于知道为了让这个方法起作用,你还需要为该签名指定冗余的方法的元数据。



这是使用函数 objc.registerMetaDataForSelector 完成的。 :

  objc.registerMetaDataForSelector(bSUPERCLASSNAME,
bgetKey: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}')
}

)$ b b

使用此函数的示例和一些详细信息可以在 test_metadata_py.py (和附近的 test_metadata * .py 文件)。



NB 必须在 c $ c> get< Key>:range: for,并且该函数需要在类定义结束之前的某个时间被调用(但是在语句本身似乎都工作)。



我基于元数据元数据 NSArray getObjects:range:在基金会PyObjC.bridgesupport文件 2 ,并通过参考Apple的 BridgeSupport联机帮助页



有了这个功能,还值得注意的是定义方法的最简单的方法是(至少,IMO):

  @ objc.signature('v @:o ^ @ {_NSRange = QQ}')
def get<#Key#> _range_(self,buf,inRange):
#NSLog(uget<#Key#>)
return self。<#Key#> .getObjects_range_(buf,inRange)

数组的内置 getObjects:range:






在32位Python上, QQ 意味着两个 unsigned long long II ,表示两个 unsigned int s

2:位于(系统/库/框架) /Python.framework/Versions/2.6/Extras/lib/python/PyObjC/Foundation/PyObjC.bridgesupport


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?

解决方案

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

这篇关于pyobjc索引访问器方法与范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆