Alamofire的使用教程
环境:Alamofire 4, Xcode 8.2, iOS 10, and Swift 3.
Alamofire是一个基于HTTP的网络请求库,适用于iOS和OSX,针对apple的基本网络请求库作了封装,简化网络请求的复杂逻辑。
Alamofire提供了request/response方法,JSON参数形式,序列化功能,以及authentication等许多特性。在本篇文章中,你可以学到通过Alamofire实现基本的数据上传和下载。
首先,下载基本的空项目:https://koenig-media.raywenderlich.com/uploads/2016/12/PhotoTagger-starter-1.zip
这个项目名称叫做PhotoTagger,当你完成了这个项目,会实现以下的效果:当你从照片库选择一张照片,并且上传到我们指定的第三方服务器,就可以实现照片的智能识别,包含照片所包含的标签,和图片的合成颜色:
下载完项目,build运行后你可以看到下面的效果。
点击select Photo按钮,当前view的背景会换成你选择的图片的样子
Imagga 的API
Imagga是一个图片识别平台,为开发者免费提供了图片的上传获取API,有兴趣可以看看Imagga平台的这个小项目。https://imagga.com/auto-tagging-demo?url=https://imagga.com/static/images/tagging/vegetables.jpg
如果想使用Imagga,首页需要注册成为其平台的开发者,填下一下的表格即可https://imagga.com/auth/signup/hacker
当填完后这个表格后,点击确定进入主页面,能看到这个页面
注意Authorization 这个部分,在以后的网络请求中会有用到。
这里是imagga的文档详细使用说明,需要的可以看看。http://docs.imagga.com/
安装 Dependencies
创建cocoaPod环境,创建Podfile文件,如下
platform :ios, '10.0'
inhibit_all_warnings!
use_frameworks!
target 'PhotoTagger' do
pod 'Alamofire', '~> 4.2.0'
end
然后在终端执行以下指令:
pod install
如果你的电脑上没有安装cocoaPods环境,查看这篇文章http://www.raywenderlich.com/97014/use-cocoapods-with-swift
关闭当前的项目,并且打开项目PhotoTagger.xcworkspace. 运行后发现还开始的页面都一样,没有变化,下面开始正式进入网络请求的介绍部分。
开始一个Alamofire请求
分为三个部分,
upload:上传multipart files和stream,file 或data
download:下载files或者重新开始一个已经开始的网络请求
,request:每一个不含文件上传和下载的Http请求。
上传 Files
打开ViewController.swift 并且引进头文件
import Alamofire
这样就可以使用Alamofire提供的function了
接着:添加一个extension到文件的最后面
// Networking calls
extension ViewController {
func upload(image: UIImage,
progressCompletion: @escaping (_ percent: Float) -> Void,
completion: @escaping (_ tags: [String], _ colors: [PhotoColor]) -> Void) {
guard let imageData = UIImageJPEGRepresentation(image, 0.5) else {
print("Could not get JPEG representation of UIImage")
return
}
}
}
这一步上传我们本地的图片到imagga的服务器,同时会返回给我们一个图片。
然后,在imagePickerController(_:didFinishPickingMediaWithInfo:)方法中的给imageView赋值image时添加以下代码:
// 1
takePictureButton.isHidden = true
progressView.progress = 0.0
progressView.isHidden = false
activityIndicatorView.startAnimating()
upload(
image: image,
progressCompletion: { [unowned self] percent in
// 2
self.progressView.setProgress(percent, animated: true)
},
completion: { [unowned self] tags, colors in
// 3
self.takePictureButton.isHidden = false
self.progressView.isHidden = true
self.activityIndicatorView.stopAnimating()
self.tags = tags
self.colors = colors
// 4
self.performSegue(withIdentifier: "ShowResults", sender: self)
})
所有的alamofire的请求都是异步的,这样就意味着UI的刷新也是异步的,下面介绍每一步的含义:
1. 隐藏上传按钮,并且展示上传的进度和activity view
2. 上传文件的时候通过progress handler 来更新上传进度条:
3.当上传完成之后,通过completion handler来更新UI
4.当上传完成之后,通过storyBoard来实现跳转。
然后 在upload(image:progressCompletion:completion:) 的image转化之后添加以下代码:
Alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(imageData,
withName: "imagefile",
fileName: "image.jpg",
mimeType: "image/jpeg")
},
to: "http://api.imagga.com/v1/content",
headers: ["Authorization": "Basic xxx"],
encodingCompletion: { encodingResult in
}
)
记着更换Basic xxx 成你自己的。
然后,在encodingCompletion的闭包里面添加以下代码:
switch encodingResult {
case .success(let upload, _, _):
upload.uploadProgress { progress in
progressCompletion(Float(progress.fractionCompleted))
}
upload.validate()
upload.responseJSON { response in
}
case .failure(let encodingError):
print(encodingError)
}
然后。在upload.responseJSON:添加以下代码
// 1.
guard response.result.isSuccess else {
print("Error while uploading file: \(response.result.error)")
completion([String](), [PhotoColor]())
return
}
// 2.
guard let responseJSON = response.result.value as? [String: Any],
let uploadedFiles = responseJSON["uploaded"] as? [[String: Any]],
let firstFile = uploadedFiles.first,
let firstFileID = firstFile["id"] as? String else {
print("Invalid information received from service")
completion([String](), [PhotoColor]())
return
}
print("Content uploaded with ID: \(firstFileID)")
// 3.
completion([String](), [PhotoColor]())
这里分步介绍每一步的含义:
1. 查看请求是否成功,如果失败,打印失败信息,并且调用completion handler。
2. 分离每一部分的数据,并查看返回的状态是否有效,如果有错误,打印失败信息,并且调用completion handler。
3. 更新UI
运行项目,选择一张图片上传,可以在打印台看到以下信息:
图片
这个时候,已经完成了基本的数据上传
数据下载
接下来就是讲刚刚上传照片的分析数据下载下来。
在ViewController的upload(image:progress:completion:):中添加以下代码
func downloadTags(contentID: String, completion: @escaping ([String]) -> Void) {
Alamofire.request(
"http://api.imagga.com/v1/tagging",
parameters: ["content": contentID],
headers: ["Authorization": "Basic xxx"]
)
.responseJSON { response in
guard response.result.isSuccess else {
print("Error while fetching tags: \(response.result.error)")
completion([String]())
return
}
guard let responseJSON = response.result.value as? [String: Any] else {
print("Invalid tag information received from the service")
completion([String]())
return
}
print(responseJSON)
completion([String]())
}
}
然后upload(image:progress:completion:) 替换completion handler为以下代码
self.downloadTags(contentID: firstFileID) { tags in
completion(tags, [PhotoColor]())
}
运行项目,上传你的文件并且查看控制台信息。如下图:
然后返回downloadTags(contentID:completion:) 并且替换.responseJSON
下的代码为以下代码
// 1.
guard response.result.isSuccess else {
print("Error while fetching tags: \(response.result.error)")
completion([String]())
return
}
// 2.
guard let responseJSON = response.result.value as? [String: Any],
let results = responseJSON["results"] as? [[String: Any]],
let firstObject = results.first,
let tagsAndConfidences = firstObject["tags"] as? [[String: Any]] else {
print("Invalid tag information received from the service")
completion([String]())
return
}
// 3.
let tags = tagsAndConfidences.flatMap({ dict in
return dict["tag"] as? String
})
// 4.
completion(tags)
运行项目,上传一张图片就可以看到以下效果:
下面开始获取图片的colors的接口,同样的:
在ViewController的downloadTags(contentID:completion:):下面添加以下代码
func downloadColors(contentID: String, completion: @escaping ([PhotoColor]) -> Void) {
Alamofire.request(
"http://api.imagga.com/v1/colors",
parameters: ["content": contentID],
// 1.
headers: ["Authorization": "Basic xxx"]
)
.responseJSON { response in
// 2.
guard response.result.isSuccess else {
print("Error while fetching colors: \(response.result.error)")
completion([PhotoColor]())
return
}
// 3.
guard let responseJSON = response.result.value as? [String: Any],
let results = responseJSON["results"] as? [[String: Any]],
let firstResult = results.first,
let info = firstResult["info"] as? [String: Any],
let imageColors = info["image_colors"] as? [[String: Any]] else {
print("Invalid color information received from service")
completion([PhotoColor]())
return
}
// 4.
let photoColors = imageColors.flatMap({ (dict) -> PhotoColor? in
guard let r = dict["r"] as? String,
let g = dict["g"] as? String,
let b = dict["b"] as? String,
let closestPaletteColor = dict["closest_palette_color"] as? String else {
return nil
}
return PhotoColor(red: Int(r),
green: Int(g),
blue: Int(b),
colorName: closestPaletteColor)
})
// 5.
completion(photoColors)
}
}
最后在upload(image:progress:completion:)的completion handler下面添加以下代码:
self.downloadTags(contentID: firstFileID) { tags in
self.downloadColors(contentID: firstFileID) { colors in
completion(tags, colors)
}
}
运行项目,并且点击colors 按钮可以看到以下效果。
项目地址:https://github.com/LINDreaming/DailyTools
原文地址:https://www.raywenderlich.com/147086/alamofire-tutorial-getting-started-2
上一篇: 记一次jconsole无法远程连接的问题
下一篇: 【C++grammar】名字隐藏与重定义