程序员随笔:使用来自服务器的图像(有源码)
如果您是移動(dòng)應(yīng)用程序開發(fā)人員,則在某個(gè)時(shí)間點(diǎn)您需要與后端進(jìn)行互動(dòng)。您可能需要做的其中一項(xiàng)任務(wù)是從服務(wù)器檢索并顯示圖像,或?qū)D像提交給該服務(wù)器。提交圖像時(shí)應(yīng)該使用什么格式?如何將從服務(wù)調(diào)用接收的字節(jié)轉(zhuǎn)換為圖像?
讓我們將整個(gè)堆棧從服務(wù)器構(gòu)建到iOS應(yīng)用程序,以了解如何實(shí)現(xiàn)。
設(shè)置后端
我們將首先構(gòu)建一個(gè)提供RESTful API?的Kitura服務(wù)器來完成兩件事:
從客戶端接收?qǐng)D像
向客戶提供最新的圖像
創(chuàng)建服務(wù)器項(xiàng)目
創(chuàng)建一個(gè)目錄,并初始化一個(gè)新的可執(zhí)行Swift包。
mkdir mkdir SwiftImageServer && cd SwiftImageServerswift package init --type executable
編輯您的Package.swift文件以指定您需要Kitura軟件包。
import PackageDescription
?
let package = Package( name: "SwiftImageServer", dependencies: [
? .Package(url: "https://github.com/IBM-Swift/Kitura.git", majorVersion: 1)
? ])
你可以運(yùn)行一個(gè)swift package fetch,你應(yīng)該看到SwiftPM克隆Kitura和它需要的一切。
旋轉(zhuǎn)xcodeproj?swift package generate-xcodeproj并讓我們編碼!
創(chuàng)建一個(gè)Kitura服務(wù)器
后端將會(huì)非常簡(jiǎn)單,所以我們只是在努力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()
三行代碼,你有一個(gè)服務(wù)器運(yùn)行。這是一個(gè)恥辱,它不能做太多。我們來解決這個(gè)問題。
從GET端點(diǎn)返回圖像
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)
}
你以為我們正在發(fā)送圖像?這看起來像一個(gè)數(shù)據(jù)對(duì)象,而不是?UIImage?這就是有趣的地方。你永遠(yuǎn)不會(huì)將圖像作為圖像發(fā)送。所有圖像都以簡(jiǎn)單易用的格式進(jìn)行數(shù)據(jù)打包。當(dāng)我們向服務(wù)器發(fā)送圖像和從服務(wù)器發(fā)送圖像時(shí),我們需要將其打包為數(shù)據(jù)對(duì)象,然后發(fā)送。我們將在iOS應(yīng)用程序中將其表示為UIImage。
注意guard let image = latestImage。在我們?cè)O(shè)置latestImage變量之前,這會(huì)失敗。讓我們構(gòu)建接收?qǐng)D像的端點(diǎn),以便設(shè)置latestImage變量。
將圖像提交給POST端點(diǎn)
接下來,我們將構(gòu)建將用于提交圖像的端點(diǎn)。
// 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")
??? }
}
我們已經(jīng)創(chuàng)建了一個(gè)端點(diǎn),該端點(diǎn)需要包含圖像數(shù)據(jù)的原始主體的POST請(qǐng)求。請(qǐng)記住,服務(wù)器只知道數(shù)據(jù),而不是UIImage,因此iOS應(yīng)用程序?qū)⒉坏貌粚D像轉(zhuǎn)換為數(shù)據(jù)對(duì)象。
這是我們的整個(gè)服務(wù)器完成!
正在運(yùn)行
需要已完成的服務(wù)器,可以關(guān)注并私信我
運(yùn)行可執(zhí)行目標(biāo)。這是矩陣式電腦屏幕,而不是×××的飯盒。
繼續(xù)運(yùn)行,我們將構(gòu)建iOS應(yīng)用程序。
客戶端應(yīng)用程序
關(guān)注我并且私信我,提供iOS應(yīng)用程序的完整示例代碼。
創(chuàng)建項(xiàng)目
創(chuàng)建一個(gè)新的Single View iOS應(yīng)用程序。我們將需要修改Info.plist。我們需要獲得訪問照片庫(kù)的權(quán)限才能選擇圖片。我們還需要修改App Transport安全設(shè)置以發(fā)出HTTP網(wǎng)絡(luò)請(qǐng)求,而不是HTTPS(我們的本地Kitura服務(wù)器為HTTP)。
將以下內(nèi)容添加到項(xiàng)目中Info.plist:
我們將添加一個(gè)按鈕,允許我們從照片庫(kù)中選擇一幅圖像,并將其提交給我們之前構(gòu)建的服務(wù)器。
我們將通過在視圖控制器中添加一個(gè)按鈕來開始Main.storyboard:
現(xiàn)在,將其掛接ViewController.swift并添加代碼以將其發(fā)布到我們的后端。
讓我們將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設(shè)置為UIImagePickerController的委托。添加一個(gè)符合委托協(xié)議的擴(kuò)展,該協(xié)議也處理任何拾取的圖像。設(shè)置委托也需要符合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)
??? }
}
我們可以選擇一張圖片,我們隨時(shí)可以處理它。注意submit(image:)上面例子中的函數(shù)。我們現(xiàn)在將創(chuàng)建該功能,并將圖像提交給我們的服務(wù)器。
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()
??? }
從服務(wù)器接收?qǐng)D像
現(xiàn)在我們可以將圖像作為數(shù)據(jù)對(duì)象提交,我們需要構(gòu)建用于接收?qǐng)D像作為數(shù)據(jù)并將其轉(zhuǎn)換為普通舊UIImage的功能。
首先在Main.storyboard中添加一個(gè)圖像視圖和另一個(gè)按鈕到視圖控制器:
當(dāng)用戶點(diǎn)擊新按鈕時(shí),我們將調(diào)用latestImage端點(diǎn)來檢索作為數(shù)據(jù)對(duì)象發(fā)送到服務(wù)器的最后一個(gè)圖像。然后我們將它轉(zhuǎn)換為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()
??? }
成品
這是我們的應(yīng)用程序已經(jīng)提交了一個(gè)圖像到服務(wù)器,并從服務(wù)器拉出一個(gè)圖像來顯示。
當(dāng)你點(diǎn)擊Pick Image時(shí),你會(huì)看到一個(gè)UIIImagePickerController,它允許你從照片庫(kù)中選擇一個(gè)圖像,并在將其轉(zhuǎn)換為數(shù)據(jù)對(duì)象后將其提交給我們的后端。“顯示最新圖像”按鈕向我們的服務(wù)器發(fā)出GET請(qǐng)求,以檢索最后發(fā)送的圖像,將其轉(zhuǎn)換為UIImage,然后將其顯示在我們的UIImageView中。
您現(xiàn)在應(yīng)該對(duì)如何將文本以外的對(duì)象發(fā)送到服務(wù)器有一個(gè)基本的了解 - 以及如何檢索它們。恭喜!
轉(zhuǎn)載于:https://blog.51cto.com/13518796/2107758
總結(jié)
以上是生活随笔為你收集整理的程序员随笔:使用来自服务器的图像(有源码)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搭建Mysql-proxy实现主从同步读
- 下一篇: Openlayers4中实现动态线效果