前兩天剛訂閱了bestswifter大大的小專欄,其中《2018 年將至,ios 工程師如何自我提高》這篇文章使我感觸頗深,最近剛好開始看python, 就萌生了寫一個(gè)python腳本練練手的想法。
1. 為什么要寫這個(gè)app?
原因之一當(dāng)然是學(xué)了點(diǎn)東西總想練練手。
更為重要的原因則是,在寫iOS app時(shí),每增加一個(gè)網(wǎng)絡(luò)請(qǐng)求,就要寫一個(gè)json對(duì)應(yīng)的model類,而構(gòu)造這些model類的代碼毫無快感可言。so,人生苦短,我用python

2. 技術(shù)棧
-
python最最最基礎(chǔ)知識(shí)
- json反序列化
將輸入的json字符串轉(zhuǎn)成對(duì)應(yīng)的字典(dict) + 數(shù)組(list)組合的形式
res = json.loads("輸入的json字符串")- 字符串操作
解析字典和數(shù)組內(nèi)容,生成swift對(duì)應(yīng)的字符串,拼接起來即可
# 遍歷字典 for (key, value) in dic.items(): # 轉(zhuǎn)換成swift格式 if isinstance(value, str): return "String" elif isinstance(value, float): return "Float" # 字符串?dāng)?shù)組拼接 result= ''.join([line+'\n' for line in res])推薦兩個(gè)不錯(cuò)學(xué)習(xí)資源:Python 簡(jiǎn)單入門指北(試讀),Python教程- 廖雪峰
- json反序列化
Cocoa APP生成
- 界面搭建
Mac OS的界面搭建和iOS超級(jí)相似,如果會(huì)iOS編程,3分鐘就能搞定,這里不做贅述。
- 圖標(biāo)生成
制作一個(gè)1024*1024的圖片,我習(xí)慣使用pixelmator,個(gè)人感覺比較簡(jiǎn)單上手,然后生成若干張對(duì)應(yīng)尺寸的圖標(biāo),這種app有很多,我用的是Prepo
- Cocoa 運(yùn)行python腳本
NSTask已經(jīng)被廢棄,應(yīng)該使用Process()執(zhí)行腳本文件
let buildTask = Process()
let outPip = Pipe()
let errorPipe = Pipe()
buildTask.launchPath = "/usr/bin/python"
// arguments是[String]類型,第一個(gè)元素應(yīng)該為xx.py的路徑,后面元素為該py接受的參數(shù)
buildTask.arguments = args
buildTask.standardInput = Pipe()
buildTask.standardOutput = outPip
buildTask.standardError = errorPipe
// 腳本執(zhí)行完畢后的回調(diào)
buildTask.terminationHandler = { p in
self.taskFinish()
}
buildTask.launch()
buildTask.waitUntilExit()
// 腳本的輸出結(jié)果,即腳本文件的print()方法打印的內(nèi)容
let data = outPip.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: String.Encoding.utf8)
// 錯(cuò)誤處理, python系統(tǒng)錯(cuò)誤
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
let errorStr = String(data: errorData, encoding: String.Encoding.utf8)
if let aError = errorStr, aError != "" {
sendError("解析錯(cuò)誤\r\n" + aError)
}
- arguments:腳本參數(shù)
let scripyPath = Bundle.main.path(forResource: "Parse", ofType: "py")! // 腳本路徑
let para1 = "input info" // 傳入?yún)?shù),通過sys.argv[I]獲取
let args = [scripyPath, para1]
buildTask.arguments = args
- standardOutput:腳本輸出
執(zhí)行腳本后可通過output獲取結(jié)果
注意:腳本的返回結(jié)果不是通過函數(shù)的return,而是通過調(diào)用print(infos)函數(shù),即infos作為結(jié)果返回
let data = outPip.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: String.Encoding.utf8)
- standardError: 錯(cuò)誤輸出
解決python的exception信息
task.terminationStatus 不等于0也能判斷為失敗
3. 封裝
Cocoa 運(yùn)行python腳本的代碼,寫起來雖然不算特別麻煩,但總也說不是簡(jiǎn)潔,于是重新封裝了一個(gè)類方便調(diào)用:CocoaPython
使用如下:
let script = CocoaPython(scrPath: pyPath)
script.runAsync()
詳細(xì)說明:
// python腳本文件路徑
guard let aPath = Bundle.main.path(forResource: "Parse", ofType: "py") else { return }
// args: py文件接受的參數(shù)列表,通過sys.argv[i]訪問
// block: 完成后的回調(diào),包括返回值和錯(cuò)誤內(nèi)容
let script = CocoaPython(scrPath: aPath, args: [""]) { [weak self] in
print($0) // 返回值,所有的py中print()的內(nèi)容
print($1) // py中的錯(cuò)誤信息
}
script.spliPara = "$" // 如果有多個(gè)結(jié)果,每個(gè)結(jié)果之間的分隔符,不設(shè)置則將所有的結(jié)果當(dāng)成一個(gè)結(jié)果返回,即result == result[0]
script.runAsync() // 異步執(zhí)行,回調(diào)在異步主線程中調(diào)用
// or script.runAsync(asyncComlete: false) // 異步執(zhí)行,回調(diào)在global中執(zhí)行
// or script.runSync() // 同步執(zhí)行
4. 資源
github地址: json2swift
OS X app: json2Swift.app
python 腳本: json2Swift.py


