Как передать NSSize и NSRect в PyObjC KVC для удобства доступа

Я пишу некоторый код AppKit в PyObjC на Lion и хочу использовать специальный стиль доступа KVC, например. obj._.field = value вместо obj.setField_(value).

Мне удалось установить свойства со значением NSString и NSDictionary с помощью KVC, но у меня возникли проблемы с обернутыми структурами Objective-C, в частности с NSSize и NSRect.

Когда я пытаюсь установить свойство KVC типа NSSize или NSRect, уровень Objective-C генерирует исключение NSInvalidArgumentException. Cocoa пытается вызвать sizeValue или rectValue для объекта Python.

Вот журнал в интерактивной подсказке, который показывает проблему:

% python
Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from AppKit import *
>>> NSApplication.sharedApplication()
<NSApplication: 0x7fcf6ae071f0>
>>> w = NSWindow.alloc().init()
>>> w._.minSize = NSSize(100, 200)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC/objc/_convenience.py", line 141, in __setattr__
    return self.__object.setValue_forKey_(value, key)
ValueError: NSInvalidArgumentException - Class OC_PythonObject: no such selector: sizeValue
>>> r = NSMakeRect(100, 200, 300, 400)
>>> w._.frame=r
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC/objc/_convenience.py", line 141, in __setattr__
    return self.__object.setValue_forKey_(value, key)
ValueError: NSInvalidArgumentException - Class OC_PythonObject: no such selector: rectValue

PyObjC, похоже, оборачивает структуры в прокси-сервер OC_PythonObject, который не реализует ожидаемый преобразователь KVC. Код KVC предполагает, что значение похоже на NSValue, и реализует методы доступа к структуре.

Есть ли способ установить свойства KVC со значением структуры в PyObjC?


person Jay Lieske    schedule 09.12.2011    source источник


Ответы (1)


Это довольно просто. Даже в простом ObjC структуры должны быть заключены в NSValue перед прохождением через KVC. Вы можете сделать то же самое в Python:

>>> w._.minSize = NSValue.valueWithSize_(NSSize(100,200))
>>> w.minSize()
<NSSize width=100.0 height=200.0>
>>> w._.frame = NSValue.valueWithRect_(NSMakeRect(100, 200, 300, 400))
>>> w.frame()
<NSRect origin=<NSPoint x=100.0 y=200.0> size=<NSSize width=300.0 height=400.0>>

См. "Wrapping and Unwrapping Structs" в Руководстве по программированию KVC для получения дополнительной информации. Кроме того, при этом не забывайте, что не все классы совместимы с KVC для всех атрибутов.

person jscs    schedule 11.12.2011
comment
@Jay: это не обходной путь. Так работает Cocoa (в частности, KVC) как в Obj-C, так и в PyObjC. - person jscs; 04.01.2012
comment
Вы правы в том, что KVC работает таким образом, и, прочитав примечания к выпуску PyObjC, я даже могу согласиться с тем, что создание объектов NSSize, несовместимых с NSValue, является преднамеренным. Тем не менее, дополнительный код, который необходимо написать, по-прежнему является обходным решением для отсутствия передачи информации между PyObjC и средой выполнения Objective-C. PyObjC передает объект Python NSSize в среду выполнения Objective-C как непрозрачный объект OC_PythonObject точно так же, как он передает объекты, не относящиеся к Cocoa Python. Если бы этот класс реализовал sizeValue или если прокси-сервер _ создал оболочку NSValue, тогда пользовательский код был бы значительно понятнее. - person Jay Lieske; 11.01.2012