若是您是移動應用程序開發人員,則在某個時間點您須要與後端進行互動。您可能須要作的其中一項任務是從服務器檢索並顯示圖像,或將圖像提交給該服務器。提交圖像時應該使用什麼格式?如何將從服務調用接收的字節轉換爲圖像?git
讓咱們將整個堆棧從服務器構建到iOS應用程序,以瞭解如何實現。github
設置後端swift
咱們將首先構建一個提供RESTful API 的Kitura服務器來完成兩件事:後端
從客戶端接收圖像xcode
向客戶提供最新的圖像安全
建立服務器項目服務器
建立一個目錄,並初始化一個新的可執行Swift包。網絡
mkdir mkdir SwiftImageServer && cd SwiftImageServerswift package init --type executablesession
編輯您的Package.swift文件以指定您須要Kitura軟件包。async
import PackageDescription
let package = Package( name: "SwiftImageServer", dependencies: [
.Package(url: "https://github.com/IBM-Swift/Kitura.git", majorVersion: 1)
])
你能夠運行一個swift package fetch,你應該看到SwiftPM克隆Kitura和它須要的一切。
旋轉xcodeproj swift package generate-xcodeproj並讓咱們編碼!
建立一個Kitura服務器
後端將會很是簡單,因此咱們只是在努力main.swift。
首先添加咱們須要的全部樣板:
import Kitura
import Foundation
// Create a Router that we can use to create REST endpoints
let router = Router()
// Specify that we want an HTTP server that we can reach with http://localhost:8090
Kitura.addHTTPServer(onPort: 8090, with: router)
// Start the server
Kitura.run()
三行代碼,你有一個服務器運行。這是一個恥辱,它不能作太多。咱們來解決這個問題。
從GET端點返回圖像
var latestImage: Data? = nil
// http://localhost:8090/latestImage
router.get("/latestImage") {
request, response, next in
defer { next() }
guard let image = latestImage else {
response.status(.preconditionFailed).send("No image is available")
return
}
response.send(data: image)
}
你覺得咱們正在發送圖像?這看起來像一個數據對象,而不是 UIImage?這就是有趣的地方。你永遠不會將圖像做爲圖像發送。全部圖像都以簡單易用的格式進行數據打包。當咱們向服務器發送圖像和從服務器發送圖像時,咱們須要將其打包爲數據對象,而後發送。咱們將在iOS應用程序中將其表示爲UIImage。
注意guard let image = latestImage。在咱們設置latestImage變量以前,這會失敗。讓咱們構建接收圖像的端點,以便設置latestImage變量。
將圖像提交給POST端點
接下來,咱們將構建將用於提交圖像的端點。
// Create a POST endpoint: http://localhost:8090/image
router.post("/image") {
request, response, next in
defer { next() }
var data = Data()
do {
// Read the body of the request into the data object
try _ = request.read(into: &data)
latestImage = data
response.status(.OK).send("Image received")
} catch(let error) {
response.status(.internalServerError)
.send("Something went wrong when reading the image data")
}
}
咱們已經建立了一個端點,該端點須要包含圖像數據的原始主體的POST請求。請記住,服務器只知道數據,而不是UIImage,所以iOS應用程序將不得不將圖像轉換爲數據對象。
這是咱們的整個服務器完成!
正在運行
須要已完成的服務器,能夠關注並私信我
運行可執行目標。這是矩陣式電腦屏幕,而不是×××的飯盒。
繼續運行,咱們將構建iOS應用程序。
客戶端應用程序
關注我而且私信我,提供iOS應用程序的完整示例代碼。
建立項目
建立一個新的Single View iOS應用程序。咱們將須要修改Info.plist。咱們須要得到訪問照片庫的權限才能選擇圖片。咱們還須要修改App Transport安全設置以發出HTTP網絡請求,而不是HTTPS(咱們的本地Kitura服務器爲HTTP)。
將如下內容添加到項目中Info.plist:
咱們將添加一個按鈕,容許咱們從照片庫中選擇一幅圖像,並將其提交給咱們以前構建的服務器。
咱們將經過在視圖控制器中添加一個按鈕來開始Main.storyboard:
如今,將其掛接ViewController.swift並添加代碼以將其發佈到咱們的後端。
讓咱們將IBAction鏈接到「Pick Image」按鈕,咱們使用UIImagePickerController來選擇圖像。
@IBAction func pickImage(_ sender: Any) {
guard UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else { return }
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
咱們將ViewController設置爲UIImagePickerController的委託。添加一個符合委託協議的擴展,該協議也處理任何拾取的圖像。設置委託也須要符合UINavigationControllerDelegate,因此也要添加它。
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
public func imagePickerController(
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String: Any]) {
if let image = info[UIImagePickerControllerOriginalImage]
as? UIImage {
submit(image: image)
} else if let image = info[UIImagePickerControllerEditedImage as? UIImage {
submit(image: image)
}
picker.dismiss(animated: true)
}
}
咱們能夠選擇一張圖片,咱們隨時能夠處理它。注意submit(image:)上面例子中的函數。咱們如今將建立該功能,並將圖像提交給咱們的服務器。
func submit(image: UIImage) {
let session = URLSession(
configuration: URLSessionConfiguration.default)
guard let url = URL(string: "http://localhost:8090/image") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = UIImagePNGRepresentation(image)
let dataTask = session.dataTask(with: request) {
(data, response, error) in
if let error = error {
print("Something went wrong: \(error)")
}
if let response = response {
print("Response: \n \(response)")
}
}
dataTask.resume()
}
從服務器接收圖像
如今咱們能夠將圖像做爲數據對象提交,咱們須要構建用於接收圖像做爲數據並將其轉換爲普通舊UIImage的功能。
首先在Main.storyboard中添加一個圖像視圖和另外一個按鈕到視圖控制器:
當用戶點擊新按鈕時,咱們將調用latestImage端點來檢索做爲數據對象發送到服務器的最後一個圖像。而後咱們將它轉換爲UIImage並將其顯示在圖像視圖中。
@IBOutlet weak var imageView: UIImageView!
@IBAction func showLatestImage(_ sender: Any) {
let session = URLSession(
configuration: URLSessionConfiguration.default)
guard let url = URL(
string: "http://localhost:8090/latestImage") else {
return
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
session.dataTask(with: request) { (data, response, error) in
if let error = error {
print("Something went wrong: \(error)")
}
if let imageData = data {
DispatchQueue.main.async {
self.imageView.image = UIImage(data: imageData)
}
}
}.resume()
}
成品
這是咱們的應用程序已經提交了一個圖像到服務器,並從服務器拉出一個圖像來顯示。
當你點擊Pick Image時,你會看到一個UIIImagePickerController,它容許你從照片庫中選擇一個圖像,並在將其轉換爲數據對象後將其提交給咱們的後端。「顯示最新圖像」按鈕向咱們的服務器發出GET請求,以檢索最後發送的圖像,將其轉換爲UIImage,而後將其顯示在咱們的UIImageView中。
您如今應該對如何將文本之外的對象發送到服務器有一個基本的瞭解 - 以及如何檢索它們。恭喜!