如何在 Swift 中使用 Alamofire 進行網絡編程
2014 年 6 月 Apple 發布 Swift 以來,如何在 Swift 中進行網絡編程一直成為程序猿們關注的焦點。甚至,Chris Lattner,Swift 的作者之一,也發推說過,在 Swift 中解析 JSON 還有很長的路要走。因此,許多人開始尋求替代方案。盡管,在 Swift 中也有處理 JSON 解析的內建類,但是對開發者來說并不是很友好。幸運的是,Alamofire 出現了。Alamofire 是一個可以幫助我們解析 JSON 的強有力網絡庫,它由 Objective-C 中同類網絡庫 AFNetworking 的作者編寫。
在這個又臭又長、近乎 3500 多詞(譯者注:in English)的教程中,我們將探討一系列廣泛的網絡基本話題,并建立一個假日待辦應用。
同時,你會從本教程中學到:如何使用和解析 JSON,如何自定義服務器端,如何使用 Heroku 和 MongoLab 等工具,HTTP 的工作原理(包括 GET,POST 和 DELETE 請求),如何使用 git 和終端(terminal)以及如何使用 Cocoapods。如果你覺得上面提到的內容太多了,那就對了,拿一杯咖啡,就讓我們開始吧。
哦,AppCoda 的所有作者祝大家節日開心!:blush:
注意:本教程是一個進階教程,涵蓋了很多東西。而且,我假設你已經對 iOS 和 Swift 有了很堅實的了解。文章中諸如 tableviews, autolayout,delegate 等話題都不會深入的解釋原理。你如果記不清這些內容,可以先去學習我們推出的 優秀課程 ,然后再回來看本教程。
開始
為了實現本教程要實現的功能,我已用 Node.js 寫了一個服務器后端。這里需要給那些對它不熟悉的人解釋一下,Node.js 是一個基于 Javascript、運行在 Google Chrome 的 V8 引擎中的運行時環境。長話短說,總之它是一個特別可靠,速度特別快,特別厲害的東西,哈哈。
為了搞定這個后端,我同時也使用了 Restify 和 MongoDB。MongoDB 是在 Web 開發人員中很流行的一個 no-SQL 數據庫。我們可以使用 MongoDB 存儲所有我們相關的數據。
當我剛開始使用 Node 的時候,我不知道這些東西都是怎么運行的,其他我所瀏覽的一些博客也從沒有解釋 Node 到底是怎么工作的。因此,盡管這是個 iOS 的博客,但我還是要介紹一下 Javascript 和 Node 服務器的工作原理。
我搜遍了網絡,都沒有一個詳細的教程引導你創建一個 API 與 iOS 應用程序交互的步驟,從現在開始就有了。
遇見 Node.js
像我之前提到的一樣,Node.js 是一個很強大的服務器端開發技術,它建立在 Chrome 的運行時環境上。因此,它是高度異步的和非阻塞的(如果你不知道我說的是什么意思,其實很簡單,大概就是:使用主線程或者應用的主要部分不會被阻塞)。多線程是一種可以防止延遲且能提高項目效率的編程技術。你把應用想象成一條高速公路,如果只有一條通道,卻有 20 輛車要通過,那么他們就很有可能會堵車。如果一條高速公路有三條都有出入口的通道,那么堵車的機會就很小。多線程就可以這樣來理解。在一個多線程的環境里,代碼執行在不同的線程就可以避免應用阻塞,從而防止程序奔潰。
Node 是由 Joyent 開發并維持的,Joyent 是一家位于舊金山的云計算公司。
如果你仍然不清楚所有這些是怎么運行的,想想后端具體干了些什么吧。下面列出來一些:
- 后端是一個為你傳送 API 的地方(我們現在正在為當前的應用構建 API,就和網絡上其他的 API 一樣,其中包括了我們在之前的 tvOS 教程 中使用的 forecast.io API)。
- MongoDB 提供了一個保存所有數據的地方。當你想要 POST 一條新的消息,我們需要有個地方可以存儲這條消息。在本教程中,我們將把這些數據存儲到 MongoDB 數據庫中。
- 創建一個功能完整的 REST API,它遵循 REST 協議。 </ol>
-
GET 請求 - GET 請求會查詢我們的數據庫,然后獲取內容。GET 請求可以被限制,使得其只能獲取一個、多個或全部的內容。事實上,每次你訪問 google.com 或瀏覽你的 非死book/推ter 主頁,你都會發起 GET 請求(可能你之前都不知道這個東西)!
</li> -
POST 請求 - POST 請求會發送數據到服務器,然后保存這個數據。舉個例子,當你在 非死book 或 推ter 上寫好文字,然后按 Post/Tweet 按鈕的時候,你就發起了 POST 請求。
</li> -
UPDATE 請求 - UPDATE 請求可以讓你修改已經存在的內容。當你編輯一條 非死book 消息時,其實使用到了 UPDATE 請求。
</li> -
DELETE 請求 - DELETE 請求會刪除對應的內容。當你按了刪除按鈕刪除 非死book 或 推ter 消息的時候,其實是調用了 DELETE 請求。
</li> </ul>以上這四個請求類型是基于 REST 協議的。Internet 能運行就是由這些請求組成的。你可能也聽說過 CRUD 這個縮寫詞,CRUD 是由 C reate, R ead, U pdate 和 D elete 的首字母組成的。很顯然,這些單詞就和 POST,GET,UPDATE 和 DELETE 是一一對應的。
帥氣!現在我們已經對 HTTP 協議有一定的理解了,我們可以進入到這次教程的核心部分了。
配置必要的工具
在我們使用 MongoLab 或 Heroku 之前,我們應該要確保 Node.js 能正常使用。
打開 Node.js官網 ,根據簡單的引導下載 Node 到你的電腦上。
然后,到 npm 官網 下載 npm。
為了正確配置我們的后端,我們需要分別在 Heroku 和 MongoLab 上注冊帳號。我們先從 MongoLab 開始吧,去 MongoLab 官網 注冊帳號。
確保選擇的是 single-node(免費),填上你數據庫的名字。我這邊取名為 alamofire-db (以 db 為后綴表示是一個數據庫,這是比較普遍的命名規范)。
接下來,登錄你的數據庫,定位好 MongoDB 數據庫的 URI。
馬上就讓你添加一個新的數據庫帳號,輸入用戶名和密碼。不要忘記密碼。
現在返回到你設置 URI 的頁面,修改成新的地址。比如:
</div>mongodb://<dbuser>:<dbpassword>@ds057954.mongolab.com:57954/alamofire-db
替換成:
</div>mongodb://gregg:test@ds057954.mongolab.com:57954/alamofire-db
MongoLab 搞定!
現在去 Heroku.com ,免費注冊后,打開 heroku toolbelt 頁面 。
跟隨指南,成功安裝后,打開終端并登錄 heroku。如果你之前從未使用過終端,不用擔心。本教程會多次使用終端,這樣你最終就會對終端的使用有一個清晰的認識。
一旦你在終端上登錄 heroku,可以使用 cd 命令(cd 代表改變目錄)進到對應目錄,將之前從 dropbox 下載的工程文件夾移動進去。
按下回車鍵就可以執行這行命令了。干的不錯,現在我們可以用 git 提交(Push) 東西到 heroku 了。
在終端中鍵入以下命令:
</div>git init git add . git commit -m "First Commit"
這三行命令,初始化了一個倉庫(repository,簡寫為 repo),并添加了當前目錄下的所有文件到這個倉庫,最終提交并保存。
git 是一款很流行的版本控制軟件。
現在你可以看終端里應該和下圖的內容差不多:
因為你之前已經成功安裝了 heroku toolbelt,所以你現在可以在終端里鍵入 heroku login ,并輸入帳號密碼。敲回車后繼續,如果帳號密碼沒問題的話,你的 Email 會以藍綠色高亮顯示。
現在,鍵入 heroku create 來創建一個新的 heroku 應用。Heroku 會創建一個新的帶有域名的應用給你。比如,我的就是 https://whispering-plains-1537.herokuapp.com/。
現在,鍵入 git push heroku master 來把你新建的應用發送到 heroku。
如果一切順利的話,會顯示如下圖(其中的某一些設置可能會不同)。
使用 Node.js, Express, MongoLab & Mongoose
讓我們從下載示例工程開始, 鏈接在這里 。打開你最喜歡的文本編輯器(我這邊用的是 Sublime Text 2;可以在 這里 下載免費版,如果你支持的話也可以購買),然后繼續。
Javascript 在很大程度上是和 Swift 很相似的。我們之后會使用 express 和 mongoose 兩個著名 node 包。請確保你已經在系統上安裝 npm 和 node 包管理器。
Express 是 Node.js 中的一個「快速、強大而又輕量級」的網絡框架,它可以輕松解決路由(Route)問題。你問什么是路由?路由就是你與網絡交互的方式。每次你打開 google.com 的時候,其實你訪問的是根主頁,即 google.com/。假如你訪問 google.com/hello,那就是另外一個路由了。我們接下來將要定義一個能訪問我們數據庫的路由。
你可以從 expressjs.org 官網上學習更多關于 express 的知識。
下面是示例代碼:
</div>var express = require('express'); // 1 var app = express(); // 2 // 當一個 GET 請求訪問主頁的時候,會返回 hello world app.get('/', function(req, res) { // 3 res.send('hello world'); // 4 });
第一行代碼設置了一個叫 express 的變量。第二行代碼,把 express 初始化后賦值給一個叫 app 的變量。在第三行代碼,app 這個變量代表了 express 環境,調用它的 get() 方法(形式類似 Swift)。當一個用戶訪問 / 根主頁的時候,就會顯示「hello world」。這是 express 作為路由的一個例子。如果需要更多信息,可以訪問 express 官網 查看。
現在,我們已經配置好了 mongo 數據庫的環境,接下來讓我們來使用 cURL 請求測試一下功能。cURL 是一款命令行程序,它可以發送 HTTP 請求。我們將會先使用 cURL 做一下實驗,然后再遷移到 Alamofire 去。
JavaScript 介紹
模型
打開你的文本編輯器(再次順便說一下,我用的是 Sublime),同時打開 app.js 文件。正如你看到的,應用被分割成了一個 model 和路由文件(就是你剛打開的 app.js 文件)。model 文件可以建立模式(schema)或數據庫結構。讓我們先來簡單看看這個文件吧。
var mongoose = require('mongoose'), Schema = mongoose.Schema;
var TodoSchema = new Schema( { name: String });
mongoose.model('employees', TodoSchema);</pre></div> </div>
我們可以使用 mongoose,它是一個用在應用與 mongo 之間作為接口的 npm 包。我起初在構建一個雇工跟蹤應用,并把 model 命名為 employee,但是可能會隨時修改這個 model。我保留著它,是因為這個教程的接下來部分可能會用到。
Mongoose 能很方便的提供與 mongoLab 的 heroku node 應用連接并提供相應的接口。這的確非常方便。
路由
路由文件里存的是我們將會 輸出 到 app.js 文件的內容。不用太擔心這個輸出——它是 node 中一個比較先進的特性,也超出了本教程的范圍。
注意第 26 行的 newTodo 。正如你可能猜到的,這行代碼創建了一個新的 todo。
var emp = new Todo(req.body);
emp.save(function(err){ if (err) { res.send('Error occurred'); return console.log(err); } res.send(emp);
});</pre></div> </div>
我們把 Todo 對象(在第四行定義了一個與 mongoose 連接的對象)賦值給一個叫 emp 的變量,并設置 req.body(req 代表請求,它會發送給我們數據,同時,res 代表回復,它會返回我們的要返回的東西)。
隨意瀏覽一下文件中剩下的方法。
就像粘稠的膠水——App.js
現在回到 app.js 文件,這里是整個應用的主要部分。接下來列出來一些這個文件里的重點部分(譯者注:對照下圖看):
- 第 13 行代碼建立 express 應用
- 第 15 - 22 行代碼配置該應用
- 第 33 行代碼使用 mongoose 將應用連接到 mongoLab 數據庫
- 第 35 行代碼建立連接
- 第 41 - 45 行代碼建立應用的路由文件并連接到 /routes/todo.js 文件
- 第 48 行代碼創建服務器 </ul>
- 構建 API
- 部署 API
- 寫客戶端應用
- 使用 HTTP 請求
- 使用 Cocoapods
- 使用 cURL
- 使用 node 和 MongoDB/Express
- 使用 Express 做路由
- 使用 Alamofire </ul>
以上這些,能讓你了解到一些 Javascript 應用的基本運作知識。但是,畢竟這篇教程不是主講 Javascript 的,我不會繼續深究。當然,我還是鼓勵你們去研究一下 express 和 mongoose。
使用 cURL
在我們的 node 應用開啟狀態下,我們可以執行一些 cURL 請求來做測試。一旦我們做完測試,就可以遷移到 Alamofire 上去了。
GET 請求
在終端里執行下面的代碼(記得將 url 修改成你自己對應的 heroku url)。
</div>curl -i -H "Accept: application/json" "https://rocky-meadow-1164.herokuapp.com/todo"
命令行中的 -i 和 -H 參數,表示我們將要接收什么東西。我們會接收 JSON 并將 JSON url 追加到請求的末尾。
你應該能看到有數據返回了。和下圖差不多。
正如你看到的,返回的數據就是我們想要得到的。如果你已經將 url 替換成你自己的,你可能什么也看不到,因為你的 mongodb 里現在還沒數據。
POST 請求
加入你想要加一些數據到數據庫里,你需要的就是下面的 POST 命令。
</div>curl -H "Content-Type: application/json" -X POST -d '{"name":"Buy Presents"}' https://rocky-meadow-1164.herokuapp.com/todo
然后,你使用之前講過的 GET 請求,就可以看到你剛才添加的「Buy Presents」的內容了。
DELETE 請求
</div>curl -X DELETE 'https://rocky-meadow-1164.herokuapp.com/todo/5657901fee93910900cc54ed'
很棒!接下去我們不會講 PUT 請求,因為在我們這個應用里暫時還用不上。但是它和其他的請求使用起來是差不多的。
使用 Alamofire 設置 iOS 應用
讓我們從新建一個名叫 TodoApp 的 Xcode 工程開始吧。因為假期就要到來,我們應該有一種方式來跟蹤這件事情。幸運的是,我們有我們的 node 應用可以幫忙。
雖然你可以手動安裝 Alamofire(通過拖拽源文件到對應工程的方法),但是我們選擇使用 Cocoapods。Cocoapods 是一款為 iOS 工程提供依賴管理的工具。在使用 Cocoapods 的時候,開發者可以輕松的添加框架或第三方類庫。如果你之前沒有使用 Cocoapods,強烈推薦你去使用。
接下來,在終端里運行以下命令可以確保你在接下來的步驟后成功安裝 Cocoapods。
</div>$ gem install cocoapods
然后,通過 cd 命令進入你工程所在的目錄,鍵入以下命令。
</div>vim Podfile
Vim 是一款系統自帶的命令行編輯器,與 Sublime Text 或 TextMate 類似。我們現在要新建一個 Podfile 的文件,Cocoapods 每次都會去這個文件里查詢是否需要更新工程的 pod(包括各種的依賴)。
在 Podfile 這個文件里鍵入如下內容:
source '
platform :ios, '8.0'
use_frameworks!
pod 'Alamofire', '~> 3.0'</pre></div> </div>
然后,按 ESC 鍵,并輸入:wq,再敲回車。其中,wq 表示保存并退出。
我們現在已經成功創建 Podfile 并且保存了,為了安裝 CocoaPods,在終端里輸入以下命令:
</div>pod install
敲了回車后,如果一切都設置好的話,大概會呈現下圖顯示的內容。
這時候,你可以看到命令行里要求你關閉當前打開的 Xcode 并且以后都用 .xcworkspace 為后綴的文件來打開工程。
下面這個命令能夠非常方便地打開當前目錄的 finder 界面。到此為止我們在 Terminal 中的操作就那么多,看上去一天之內有那么多就夠了!
</div>open .
打開 ViewController.swift,讓我們繼續吧。
Alamofire GET 請求
在打開的 ViewController.swift 里,輸入以下代碼來導入 Alamofire:
</div>import Alamofire
在 viewDidLoad() 方法里鍵入以下代碼來使用 Alamofire。
Alamofire.request(.GET, "
if let JSON = response.result.value { print("JSON: \(JSON)") }
}</pre></div> </div>
在第一行代碼中,我們聲明了一個 GET 請求,并且傳入了一個我們需要的 URL。運行當前的應用,看看返回的是什么。如果一切都設置正確的話,你會看到返回的是 JSON 數據。
現在,打開 Main.storyboard,添加一個 tableview 到 view controller,并將視圖控制器嵌入到 navigation controller。你的 storyboard 現在看起來應該跟我的一樣,如下圖(值得注意的是,現在返回的 JSON 數據還只是顯示在控制臺上,我們要將其顯示出來。)。
將以下代碼復制并粘帖到你的 Viewcontroller.swift 文件里。
import UIKit import Alamofire class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView! var jsonArray:NSMutableArray? var newArray: Array<String> = [] override func viewDidLoad() { super.viewDidLoad() Alamofire.request(.GET, "https://rocky-meadow-1164.herokuapp.com/todo") .responseJSON { response in print(response.request) // original URL request print(response.response) // URL response print(response.data) // server data print(response.result) // result of response serialization if let JSON = response.result.value { self.jsonArray = JSON as? NSMutableArray for item in self.jsonArray! { print(item["name"]!) let string = item["name"]! print("String is \(string!)") self.newArray.append(string! as! String) } print("New array is \(self.newArray)") self.tableView.reloadData() } } // Do any additional setup after loading the view, typically from a nib. }
}</pre></div> </div>
我初始化了兩個數組 jsonArray 和 newArray,用 for 循環遍歷了返回數據的那個 jsonArray,將其中的每個數據保存到 newArray 中。
我使用 POST cURL 請求在數據庫里多添加了一些數據。用法類似,不再贅述。
你可以試試下面代碼演示的 GET 請求的極致精簡寫法。
</div>Alamofire.request(.GET, "https://rocky-meadow-1164.herokuapp.com/todo").responseJSON { response in debugPrint(response) }
接下來,在文件頂部的 UIViewController 定義后面添加 UITableViewDelegate 和 UITableViewDataSource。并且,在 viewDidLoad() 方法里鍵入如下代碼:
</div>self.tableView.dataSource = self self.tableView.delegate = self
最后,添加 UITableView 的 delegate 方法。
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.newArray.count }
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = self.newArray[indexPath.row] return cell
}
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. }</pre></div> </div>
正如你看到的,我們的 tableview 已經成功顯示數據了。
現在,讓我們來添加一個按鈕,用來添加數據到列表中。首先,先在 storyboard 里添加一個叫 AddViewController 的類,并用 segue 的方式連接起來。你的 storyboard 應該和下圖差不多。
Alamofire POST 請求
在你的 AddViewController.swift 文件里,為 textfield 建立一個 IBOutlet(命名為 textView)和為 Save 按鈕建立一個 IBAction。在 Save 按鈕代碼下面鍵入如下代碼:
Alamofire.request(.POST, "
self.navigationController!.popViewControllerAnimated(true)</pre></div> </div>
正如你看到的,Alamofire 大大簡化了發送 POST 請求的過程。
接下來,我們來對 ViewController.swift 文件進行重構,確保我們在保存數據后能及時更新列表。刪除 viewDidLoad() 方法里 GET Alamofire 的代碼,用以下的 downloadAndUpdate 方法代替。
func downloadAndUpdate() { Alamofire.request(.GET, "
if let JSON = response.result.value { self.jsonArray = JSON as? NSMutableArray for item in self.jsonArray! { print(item["name"]!) let string = item["name"]! print("String is \(string!)") self.newArray.append(string! as! String) } print("New array is \(self.newArray)") self.tableView.reloadData() } } }</pre></div>
</div>
現在,在 viewWillAppear() 方法里調用這個方法,如下。
</div>override func viewWillAppear(animated: Bool) { self.downloadAndUpdate() }
如果你再次編譯并運行這個應用,就會發現每次添加新的 todo 后都會重新加載。但是,這是為什么呢?
這就關系到 view controller 的生命周期,這里我就簡短討論一下。viewDidLoad() 會在 view 初始化后并且所有控件都結束加載后被調用。問題就出在,當你從已經加載的 ViewController 上加載另外一個 view(比如 AppViewController)時,viewDidLoad 方法不會被調用(之前已經初始化過)。viewWillAppear 方法會在每次 view 在屏幕上顯示時調用。因為我們需要在再次顯示 ViewController.swift 時候顯示,所以這個方法剛好可用。
Alamofire DELETE 請求
現在在剛才的 newArray 下面添加一個 IDArray。
</div>var IDArray: Array<String> = []
接下來,更新 downloadAndUpdate 方法的相應部分,代碼如下。
self.newArray.removeAll() // NEW self.IDArray.removeAll() // NEW
添加 commitEditingStyle 方法,以調用 DELETE 請求來刪除對應的不需要數據。
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { print("ID is (self.IDArray[indexPath.row])")
Alamofire.request(.DELETE, "https://rocky-meadow-1164.herokuapp.com/todo/\(self.IDArray[indexPath.row])") self.downloadAndUpdate() } else if editingStyle == .Insert { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view } }</pre></div>
</div>
正如你看到的,以上代碼遵循了我們應用的 API,即通過傳入 /todo/ID 來調用 DELETE 請求刪除對應的數據。
同時,我們用比較簡單的 Alamofire 方法來調用 DELETE 請求并刪除了對應的數據。
至此,你現在已經擁有了一個功能完備的 todo 應用了。因此,讓我們來總結一下本次教程吧。
小結
本教程探索了很多東西。從 Javascript 的 node 到 express,從 MongoDB 到 cURL,從終端到 Cocoapods,以及最后的 Alamofire,我們深入了解了 REST API 的創建過程和網絡的工作流程。你通過本次教程應該已經堅實的掌握了以下內容:
這真是一個大教程,我感謝你堅持和我走到這里。所有的源代碼可以在 這里 下載,其中包含了 node 應用和 iOS 應用。
有任何問題和想法都可以在教程下面留言評論。下次見!
本文由 SwiftGG 翻譯組翻譯,已經獲得作者翻譯授權,最新文章請訪問http://swift.gg。
</div> </div> 原文 http://swift.gg/2015/12/22/alamofire-beginner-guide/本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!相關經驗
相關資訊
sesese色
我們的 MongoDB 放在 MongoLab 的主機上,Node 服務器放在 Heroku 上。Heroku 由 Salesforce 提供支持,可以作為 Node,Rails,Python等應用的主機服務商。MongoLab 也是一家可以當 MongoDB 主機的服務商。
HTTP 請求介紹
在我們開始寫代碼之前,你應該了解 HTTP 請求以及如何在我們的應用里使用。