若是您是移动应用程序开发人员,则在某个时间点您须要与后端进行互动。您可能须要作的其中一项任务是从服务器检索并显示图像,或将图像提交给该服务器。提交图像时应该使用什么格式?如何将从服务调用接收的字节转换为图像?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中。
您如今应该对如何将文本之外的对象发送到服务器有一个基本的了解 - 以及如何检索它们。恭喜!