Правила преобразования кода в PyObjC
PyObjC — это бридж, мостик, связующая библиотека между Python и Objective-C. Он позволит вам писать приложения на Питоне, которые используют и расширяют функционал существующих библиотек и классов Objective-C, что не мало важно, в том числе и библиотеки Cocoa. Apple включала в состав XCode бриджи начиная с Mac OS 10.0, когда предоставила возможность писать приложения с использованием Java, в 10.4 — JavaScript (для виджетов). На данный момент существуют бриджи для многих языков, но в стандартную поставку с XCode включены бриджи для Java, JavaScript, Python и Ruby, снабженные примерами использования этих языков.
Так как вся документация и примеры кода на developer.apple.com (этакий MSDN для Mac OS) написана для Objective-C, то нам потребуется соблюдать ряд правил преобразования кода, чтобы он работал с использованием Python.
- Правило преобразования имен методов
Объекты в Objective-C общаются между собой путем отправки сообщений. Для посылки сообщений используется следующий синтаксис:
[receiver message];
где receiver — указатель на объект, а message — имя вызываемого метода. После преобразования в код питона это будет выглядеть следующим образом:
receiver.message()
Примеры преобразования для разных случаев исходного кода:
# Эквивалент для метода принимающего один параметр: # # [helloString stringByAppendingString:@"world"]; # helloString.stringByAppendingString_(u"world") # При передаче множества параметров: # # [myObject makeGroup: obj1, obj2, obj3]; # myObject.makeGroup_(obj1, obj2, obj3) # Для именованных параметров название процедуры в Питоне будет складываться # из имени метода и имен параметров с добавлением нижнего подчеркивания # к имени каждого из них. # # [myRect setWidth:10 height:20]; # receiver.setWidth_height_(10, 20)
-
Правило работы с NSError**
NSError — класс, который предоставляет доступ к расширенной информации об ошибках. Некоторые функции принимают параметр этого типа в вызове своих методов, как в приведенном ниже примере, и возвращают указатель на объект NSError, если произошла ошибка, или nil (эквивалент None в Python), если функция отработала без проблем.
NSError *error; NSString *names = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames" encoding:NSASCIIStringEncoding error:&error]; if(error == nil) { NSLog(@"Successfully read names: %@", names); } else { NSLog(@"Encountered an error attempting to read names: %@", [error description]); }
К сожалению, PyObjC не может корректно обработать подобные вызовы. Поэтому в случае вызова метода, берущего параметр типа NSError**, опускайте его в своем коде. PyObjC самостоятельно отследит использование объекта NSError, динамически создаст его и приложит к возвращаемым результатам метода в виде кортежа.
names, error = NSString.stringWithContentsOfFile_encoding_error_( u"/usr/share/dict/propernames", NSASCIIStringEncoding) if(error == None): NSLog(u"Successfully read names: "+names) else: NSLog(u"Encountered an error attempting to read names: "+error.description())
-
Создание экземпляров объектов
Создание экземпляра объекта (а все объекты в Mac OS являются производными от NSObject) отличается от привычных способов создания объекта в Питоне:
myPythonObject = MyPythonClass()
Создание нового объекта разбивается на два шага: выделение памяти и инициализация объекта. Первый шаг реализуется методом alloc, который выделяет необходимое количество памяти, и возвращает указатель на выделенную под объект память. Вторая часть — вызовом метода инициализации, обычно init (обратите внимание, это обычный, ничем не отличающийся от других, метод).
Довольно часто у объектов бывает сразу несколько методов, начинающихся с init, например init, initWithString, initWIthContentsOfFile и т.д. Установившейся практикой в таком случае является выделение среди всех init-методов одного, называемого designated initializer. Все остальные init-методы должны вызывать его и только он вызывает унаследованный init метод.
Создание объекта.
myString = NSString.alloc().init()
Многие Objective-C классы содержат методы, выполняющие двухпроходную инициализацию за вас. Например:
# Эквивалент: # # myObject = NSObject.alloc().init() # myObject = NSObject.new() # Эквивалент: # # myDict = NSDictionary.alloc().init() # myDict = NSDictionary.dictionary() # Эквивалент: # # myString = NSString.alloc().initWithString_(u'my string') # myString = NSString.stringWithString_(u'my string')
Более подробную информацию о существующих для объекта методах инициализации можно найти в документации.
Вы также должны соблюдать данное соглашение при создании производных от Objective-C классов. В своем конструкторе вы должны явно вызвать инициализирующую функцию класса, который вы наследуете.
class MyClass(NSObject): def init(self): # В оригинальной документации, поставляемой с XCode для PyObjC # вас просят инициализировать родительский класс вызовом # # self = super(MyClass, self).init() # # Как я понял, документация была написана года два назад, когда # у Питона не было нормально реализовано наследование классов и # встречались такие извращения при инициализации как это: # # class A: # def method(self): # print "Hi: A" # class B(A): # __baseclass = A # def method(self): # print "Hi: B" # self.__baseclass.method(self) # # Посему предлагаю использовать стандартный для Питона # способ вызова родительского конструктора self = NSObject.init(self) if self is None: return None self.myVariable = 10 # В отличие от конструктора класса в Питоне инициализатор # должен возвращать self return self
В более глубокие детали программирования и рекомендации по построению кода на Питоне под Маком мы погрузимся в последующих постах.
Комментарии
Жень, http://www.zoitz.com/archives/36 видел? :)
Форма комментирования для «Правила преобразования кода в PyObjC»