2009-09-03 2 views
3

Я пытаюсь реализовать индексированный метод доступа для моего класса модели в Python, согласно the KVC guide. Я хочу использовать дополнительный метод дальнего действия, чтобы сразу загрузить несколько объектов по соображениям производительности. Метод берет указатель на буфер C-массива, который мой метод должен копировать в объекты. Я пробовал что-то вроде следующего, что не работает. Как это сделать?pyobjc проиндексированный метод доступа с диапазоном

@objc.accessor # i've also tried @objc.signature('[email protected]:o^@') 
def getFoos_range_(self, range): 
    return self._some_array[range.location:range.location + range.length] 

Редактировать: Я наконец-то нашел type encodings reference после Apple, переехал все документы. Прочитав это, я пробовал это:

@objc.signature('[email protected]:N^@@') 
def getFoos_range_(self, buf, range): 

но это, похоже, тоже не работало. Первый аргумент должен быть указателем на C-массив, но длина неизвестна до времени выполнения, поэтому я не знал точно, как построить правильную кодировку типа. Я попробовал '[email protected]:N^[[email protected]]@', чтобы посмотреть, и это тоже не сработало.

Мой объект модели привязан к контенту ContentArray NSArrayController, управляющего табличным представлением. По-видимому, он вообще не вызывает этот метод, возможно потому, что он ожидает другую подпись, чем та, которую предоставляет мост. Какие-либо предложения?

ответ

2

Вы были близки. Правильно декоратора для этого метода является:

@objc.signature('[email protected]:o^@{_NSRange=QQ}') 

NSRange не является объектом, но структура, и не может быть определен просто как @; вам необходимо включить членов .

К сожалению, это еще не конец. После большого количества экспериментов и поиска по источнику 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 (и около test_metadata*.py файлов) в источнике PyObjC.

N.B., что метаданные должны быть указаны в суперклассе того класса, который вас интересует при реализации get<Key>:range:, а также что эту функцию нужно вызывать когда-то до конца вашего определения класса (но либо до, либо перед оператором class сами оба, похоже, работают). Я еще не озадачил эти биты.

Я на основе этих метаданных на метаданные для NSArray getObjects:range: в Фонд PyObjC.bridgesupport файл , и помог, ссылаясь на Apple, BridgeSupport manpage.

С этим разработаны, это также стоит отметить, что самый простой способ определить метод (по крайней мере, ИМО):

@objc.signature('[email protected]: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 s
2: Находится (на Snow Leopard) по адресу:/System/Library/Frameworks/Python.framework/Версии/2.6/Дополнительно/lib/python/PyObjC/Foundation/PyObjC.bridgesupport