怎樣使用Swift創建命令行腳本(2)
-
作者: Ben Snider
( part 1譯文 )
歡迎回來!在上一節中,我們已經講述了使用Swift語言搭配 OptionKit 來創建一個簡單的命令行腳本。在本節中(最后一節)。我們將整理所有的思路,然后在之前已經創建的基于Apple Foundation的類中的方法來實現我們的BTC(比特幣)命令行價格查詢器。
回顧第一部分,我們學會了如何:
-
從命令行直接調用Swift腳本
-
使用 Carthage 管理帶有Swift腳本的庫
-
使用OptionKit框架來解析命令行參數
在這篇博客中,我們將學習到如何利用上述所有來創建一個Swift腳本查詢BTC的價格。同時也將學到怎樣使用一個URL從 BitStamp API 中請求數據,然后解析這些請求回來的JSON數據,最后為用戶打印出他們需要的結果信息。當然我們也能夠看到,怎么編譯這些Swift腳本--為一個可執行的二進制以便節約執行時間。
完成后,我們就有了一個能夠打印出最新BTC美元價格的腳本了,你還可以添加參數來指定計算價格的時間區間.這個區間參數,我們可以指定為最新(默認),每小時,以及“ vwap ”等類型。OptionKit生成的幫助信息也能夠告訴我們關于如何調用這些腳本。不出意外,我們應該可以像下面這樣運行:
$ ./btc.swift 335.45$ ./btc.swift --interval hourly 338.27</pre>
命令行參數
首先,讓我們先定義將如何接受用戶輸入。使用OptionKit,我們可以很容易的進行設置。基于之前演示的options.swift的修改版本,我將創建一個新的文件btc.swift,文件中包含如下代碼:
![]()
正如我們所看到的,它與之前的option.swift腳本及其相似。最大的區別在于這我們是從一個方法的返回值中獲取到—interval參數的。這樣我們封裝參數解析邏輯,所以我們就可以專注于實現其他功能。
于此同時,我們還需要花點時間來將從OptionKit得到的interval可選字符串,轉換為Swift 枚舉類型,便于后面方便使用。我們只需要寫如下一些簡單的代碼就可以來實現:
![]()
URL載入
到目前為止,我們已經完成了參數解析,下一步工作就是根據用戶選擇的interval類型來加載URL。通過BitStamp,實際上是兩個具有相同的JSON返回格式的URL。接下來,我們編寫一個函數,確定正確的URL并使用Foundation框架中的NSURLSession類來發起一個網絡請求。
在實現URL加載之前,我們需要實現調用函數,因此要考慮有哪些數據要傳遞。
![]()
在這里可以看到這些仍然建立在參數解析函數中,雖然開始調用實際的方法來檢索和解析價格數據。我選擇實現帶有一個閉包作為參數的retrievePriceData函數。當網絡請求完成之后(無論成功還是失敗),閉包將會被調用。傳遞給閉包的參數是可選類型的,這可以讓我們在網絡成功或者失敗情況下,分別對這兩種情況進行處理。也有可能對實際響應返回的數據解析失敗,所以parsePrice的返回值也是可選的。
這樣帶有if let block是一個很好的封裝處理,如果一切順利,將會打印出獲取的價格。
接下來我們開始著手說說如何實現retrievePriceData方法。核心就是使用基于Foundation框架的NSURLSession類來完成實際的網絡請求。如果網絡請求成功,將可以通過所提供的閉包返回NSData類型的數據給調用者,否則就只需要返回nil值。
func bitstampURL(interval: IntervalType) -> NSURL { if (interval == .LastIntervalType || interval == .VWAPIntervalType) { return NSURL(string: " } else { return NSURL(string: " } }func retrievePriceData(interval: IntervalType, completion: NSData? -> Void) -> Void { let url = bitstampURL(interval), request = NSURLRequest(URL: url), session = NSURLSession.sharedSession(), semaphore = dispatch_semaphore_create(0)
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in if error == nil { completion(data) } else { completion(nil) } dispatch_semaphore_signal(semaphore) } task.resume() dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}</pre>
這里比較復雜的地方就是,命令行腳本的執行,會在最后一個函數返回后結束。然而,NSURLSession提供給我們的是一個異步的接口,在網絡調用完成之前,這個方法就已經返回。所以為了解決這一點,我們需要使用 GCD 的信號燈( semaphore )來阻塞主線程,直到網絡請求完成。
JSON解析
我們剩下的最后一個任務就是解析retriecePriceData返回的數據,我們將使用parsePrice函數對之進行解析。我們通過BitStamp API獲取的數據是如下JSON格式:
{ high: "502.00", last: "446.02", timestamp: "1446693126", bid: "446.03", vwap: "445.3", volume: "108095.47008023", low: "368.11", ask: "446.60", open: 407.99 }我們主要關注的是last和vwap屬性,但是需要解析整個對象為字典類型數據,然后返回我們所關注的值即可。所以,我們接下來使用Foundation框架中帶有一些有條件的費覆蓋的NSJSONSerialization類,來進行處理:
func priceKey(interval: IntervalType) -> String { if (interval == .LastIntervalType || interval == .HourlyIntervalType) { return "last" } else { return "vwap" } }func parsePrice(interval: IntervalType, data: NSData) -> Double? { do { let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) if let priceData = json as? Dictionary, priceString = priceData[priceKey(interval)] as? String { // Using the failable initializer to convert to a Double? return Double(priceString) } } catch { // died parsing the JSON } return nil }</pre>
運行和編譯 我們已經完成準備工作了!全部的 entire script 源碼都在我們的github上,可以給你提供一些參考。它實現了我們最初設想的所有需求,為了更清楚的看到效果,我們來運行看看:
$ ./btc.swift -i vwap 333.95$ ./btc.swift --interval hourly 334.05</pre>
使用上面這些命令,我們已經可以把程序作為一個腳本來運行:Swift能夠動態編譯和執行它。如果我們想要直接編譯btc.swift成可執行文件,然后運行它。
在我做過多次嘗試之后發現,它不能使用swiftc動態鏈接到第三方庫。雖然可以正常編譯btc.swift腳本,但是在運行的時候,還是不能引用到OptionKit框架。我懷疑移除OptionKit依賴或許能夠正常編譯這個腳本。如果有人知道怎么能讓這個正常工作,那就太感謝了。
你可以用下面的命令來編譯執行,這樣就能看到,在運行的時候報錯了:
# Compile using swiftc $ xcrun -sdk macosx swiftc -F Carthage/Build/Mac/ btc.swift -o btcAttempt to run
$ ./btc dyld: Library not loaded: @rpath/OptionKit.framework/Versions/0/OptionKit</pre>
總結
除了把腳本編譯成可執行文件外,我們已經完成了全部工作。我們已經解決了加載第三方庫、解析命令行參數、加載遠程的JSON數據以及將這些JSON數據解析成我們能夠熟練操縱的Swift數據類型。到此,已經編寫好了一個可運行的腳本來通過BitStamp監測比特幣的價格。通過完成這個功能,我們也了解到了一些Swift語言的新特性。
所以,通過這樣一個專題的講解,我希望你們都認同專題中預期的結論,同時也能夠學到更多的新知識。我個人希望這個專題作為Swift腳本語言開發的一個入門實例,當我們使用命令行腳本時,幫助解決我們所面臨的一些比較常見的問題。感謝蘋果公司為我們提供這樣一種非常棒的編程語言,它不僅能夠非常靈活簡潔地讓我們開發一個復雜的iOS應用,也支持像我們上面所寫的例子中使用更加簡單的腳本進行編程。我很期待Swift腳本能更多應用在其他的方面,希望Swift的開源發布,能夠使Swift腳本進入到Linux系統一個新的起點。
更多譯者翻譯文章,請查看: http://www.cocoachina.com/special/translation/
本文僅用于學習和交流目的,轉載請注明文章譯者、出處和本文鏈接。
感謝 博文視點 對本期活動的支持
![]()