我用Xcode +python寫的第一個OS X app

Ashen發表於2017-11-09

前兩天剛訂閱了bestswifter大大的小專欄,其中《2018 年將至,ios 工程師如何自我提高》這篇文章使我感觸頗深,最近剛好開始看python, 就萌生了寫一個python指令碼練練手的想法。

1. 為什麼要寫這個app?

原因之一當然是學了點東西總想練練手。
更為重要的原因則是,在寫iOS app時,每增加一個網路請求,就要寫一個json對應的model類,而構造這些model類的程式碼毫無快感可言。so,人生苦短,我用python


2. 技術棧

python最最最基礎知識

1. json反序列化

將輸入的json字串轉成對應的字典(dict) + 陣列(list)組合的形式

  res = json.loads("輸入的json字串")複製程式碼

2. 字串操作

解析字典和陣列內容,生成swift對應的字串,拼接起來即可

    # 遍歷字典
    for (key, value) in dic.items():

    # 轉換成swift格式
    if isinstance(value, str):
        return "String"
    elif isinstance(value, float):
        return "Float"

    # 字串陣列拼接
    result= ''.join([line+'\n' for line in res])複製程式碼

推薦兩個不錯學習資源:Python 簡單入門指北(試讀)Python教程- 廖雪峰

Cocoa APP生成

1. 介面搭建

Mac OS的介面搭建和iOS超級相似,如果會iOS程式設計,3分鐘就能搞定,這裡不做贅述。

2. 圖示生成

製作一個1024*1024的圖片,我習慣使用pixelmator,個人感覺比較簡單上手,然後生成若干張對應尺寸的圖示,這種app有很多,我用的是Prepo

3. Cocoa 執行python指令碼

NSTask已經被廢棄,應該使用Process()執行指令碼檔案
```
let buildTask = Process()
let outPip = Pipe()
let errorPipe = Pipe()

buildTask.launchPath = "/usr/bin/python"
// arguments是[String]型別,第一個元素應該為xx.py的路徑,後面元素為該py接受的引數
buildTask.arguments = args
buildTask.standardInput = Pipe()
buildTask.standardOutput = outPip
buildTask.standardError = errorPipe
// 指令碼執行完畢後的回撥
buildTask.terminationHandler = { p in
self.taskFinish()
}
buildTask.launch()
buildTask.waitUntilExit()

// 指令碼的輸出結果,即指令碼檔案的print()方法列印的內容
let data = outPip.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: String.Encoding.utf8)

// 錯誤處理, python系統錯誤
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
let errorStr = String(data: errorData, encoding: String.Encoding.utf8)
if let aError = errorStr, aError != "" {
sendError("解析錯誤\r\n" + aError)
}


- arguments:指令碼引數
>let scripyPath = Bundle.main.path(forResource: "Parse", ofType: "py")! // 指令碼路徑
let para1 = "input info" // 傳入引數,通過sys.argv[I]獲取
let args = [scripyPath, para1]
buildTask.arguments = args

- standardOutput:指令碼輸出
> 執行指令碼後可通過output獲取結果
注意:指令碼的返回結果不是通過函式的return,而是通過呼叫print(infos)函式,即infos作為結果返回
let data = outPip.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: String.Encoding.utf8)

- standardError: 錯誤輸出
>解決python的exception資訊
task.terminationStatus 不等於0也能判斷為失敗
***

## 3. 封裝
  Cocoa 執行python指令碼的程式碼,寫起來雖然不算特別麻煩,但總也說不是簡潔,於是重新封裝了一個類方便呼叫:[CocoaPython](https://github.com/515783034/json2swift/blob/master/json2Swift/CocoaPython.swift)
使用如下:
```swift
let script = CocoaPython(scrPath: pyPath)
script.runAsync()複製程式碼

詳細說明:

// python指令碼檔案路徑
guard let aPath = Bundle.main.path(forResource: "Parse", ofType: "py") else { return }

// args: py檔案接受的引數列表,通過sys.argv[i]訪問
// block: 完成後的回撥,包括返回值和錯誤內容
let script = CocoaPython(scrPath: aPath, args: [""]) { [weak self] in
    print($0) // 返回值,所有的py中print()的內容
    print($1) // py中的錯誤資訊
}

script.spliPara = "$" // 如果有多個結果,每個結果之間的分隔符,不設定則將所有的結果當成一個結果返回,即result == result[0]
script.runAsync() // 非同步執行,回撥在非同步主執行緒中呼叫
// or script.runAsync(asyncComlete: false) // 非同步執行,回撥在global中執行
// or script.runSync() // 同步執行複製程式碼

4. 資源

github地址: json2swift
OS X app: json2Swift.app
python 指令碼: json2Swift.py

相關文章