2014年3月15日星期六

Python in iOS

上回提到,用Python作為iOS的library,計算arbitrary-precision,今集全面講解制作方法。

首先當然要download Python-iOS,git或zip 均可。

然後在Xcode,File → New → Workspace,加入自己的project (ModCalc) 和Python-iOS中的libPython project。

在ModCalc project的Build Settings,找尋Header Search Paths,加入在libPython project的path和sub-directory "include"。

選擇libPython project,因為這project已有一段時間沒有update,所以要行menu Editor → Validate Settings,update project的build setting。每次upgrade完Xcode也要行一次。

然後在ModCalc project,Build Phases,Targets,選擇ModCalc target。在Link Binary With Libraries,加入liblibPython.a。

有了header和library,還欠Python中的Standard library,即是那些Python script,那些全部zip了在Python-iOS example project (Python-iOS-app)中的python directory,將整個directory加到project ModCalc中。

完成後的project layout如下圖:

然後寫Python script作為app的model,並將之放在python/lib/python2.7/site-packages/中。以後script有任何改動,也要行Product → Clean一次,再Build,否則改動不會出現。

好了,可以寫Objective-C call Python script了。先在File → New,新增一個Objective-C class作為model,在這個class,

#include "Python.h"

然後在class的init,參照Python-iOS example project的做法init Python environment,

        // Init Python environment
        NSString* fullpath = [[NSBundle mainBundle] pathForResource:@"python" ofType:nil inDirectory:nil];
        char home[1024];
        strcpy(home, [fullpath UTF8String]);
        Py_SetPythonHome(home);

        Py_Initialize();

若然有custom script在site-packages中,可以用以下方法import

        PyRun_SimpleString("import modmath\n");

在Python中每次執行完的result是PyObject,在Objective-C中我以NSString儲存,所以寫了兩個method,一個是NSString → int PyObject,和PyObject → NSString。

- (PyObject*)PyIntFromString:(NSString*)string {
    char array[1024];
    strcpy(array, [string UTF8String]);
    return PyInt_FromString(array, NULL, 10);
}

- (NSString*)stringFromPyObject:(PyObject*)obj {
    return [NSString stringWithUTF8String:PyString_AsString(PyObject_Str(obj))];

}

跟著是計算基本的加減乘除工作,每個built-in operation都有相應的C function,但因為懶的關係,全部組合成string用PyEval_EvalCode便算了。

- (NSString*)evaluateString:(NSString*)format, ... {
    va_list args;
    va_start(args, format);
    NSString *str = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);
    PyCodeObject* code = (PyCodeObject*)Py_CompileString([str UTF8String], "test", Py_eval_input);
    return [self stringFromPyObject:PyObject_Str(PyEval_EvalCode(code, self.globalDict, self.globalDict))];

}

這樣便完成了在Objective-C中行Python script,其實並沒有想像般困難。但這個Python的version是2.7.5,下次試試自行build Python 3.4先。以上所有code也在GitHub中。

1 則留言:

  1. 你好,我下载了您的代码,现在有个问题,如何将Python换成最新的版本?

    回覆刪除