文章目录
  1. 1. 上篇地址
  2. 2. 获取数据
  3. 3. 优化 PhotoTagger
  4. 4. 最终工程代码
    1. 4.1. 下载地址
    2. 4.2. 原帖地址

上篇地址

获取数据

在 ViewController 的 extension 里面,uploadImage(_:progress:completion:) 的下面添加如下的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func downloadTags(contentID: String, completion: ([String]) -> Void) {
Alamofire.request(
.GET,
"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: AnyObject] else {
print("Invalid tag information received from service")
completion([String]())
return
}
print(responseJSON)
completion([String]())
}
}

同样把 Basic xxx替换为你自己的 token,设置好 URL 以及对应的参数。

下一步,返回 uploadImage(_:progress:completion:) 替换 completion中的代码:

1
2
3
self.downloadTags(firstFileID) { tags in
completion(tags: tags, colors: [PhotoColor]())
}

编译运行你的工程,上传一个文件,之后你在控制台就会看见返回的数据:

Imagga-Tagging-Response.png

你不用关心 confidence 的分数,在本次教程中我们只使用 tag 的名称。
下一步,返回 downloadTags(_:completion:) 然后用下面的代码替换里面的 .responseJSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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: AnyObject],
results = responseJSON["results"] as? [AnyObject],
firstResult = results.first,
tagsAndConfidences = firstResult["tags"] as? [[String: AnyObject]] 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)

下面是每步的代码:

  1. 检查响应是否成功;如果不成功,输出错误信息并调用 completion
  2. 对返回 json 数据进行解析。
  3. 迭代 tagsAndConfidences 数组,检索 tag.
  4. 调用 completion

注意:
你使用 Swift 的 flatMap 方法来进行迭代,这个方法在遇到值为 nil 的情况不会崩溃,并且会从返回结果中移除为 nil 的值。这可以让你使用条件解包(as?)来验证字典的值是否可以转换为一个字符串。

再一次编译运行你的工程,选择一涨图片,然后你会看到下面的界面:

PhotoTagger-tags.png

在 ViewController extension downloadTags(_:completion:) 下面添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
func downloadColors(contentID: String, completion: ([PhotoColor]) -> Void) {
Alamofire.request(
.GET,
"http://api.imagga.com/v1/colors",
parameters: ["content": contentID, "extract_object_colors": NSNumber(int: 0)],
// 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: AnyObject],
results = responseJSON["results"] as? [AnyObject],
firstResult = results.first as? [String: AnyObject],
info = firstResult["info"] as? [String: AnyObject],
imageColors = info["image_colors"] as? [[String: AnyObject]] 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,
g = dict["g"] as? String,
b = dict["b"] as? String,
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)
}
}

最后,返回 uploadImage(_:progress:completion:)方法,在 completion 里面的 success 的情况,添加下面的代码:

1
2
3
4
5
self.downloadTags(firstFileID) { tags in
self.downloadColors(firstFileID) { colors in
completion(tags: tags, colors: colors)
}
}

再一次编译运行你的工程,选择一涨图片,然后你会看到下面的界面:
PhotoTagger-colors.png

优化 PhotoTagger

你可能已经注意到了,在 PhotoTagger 里面有重复代码。

Alamofire 提供了一个简单的方法来排除重复的代码并且提供集中配置。这就需要创建一个结构体,遵循 URLRequestConvertible 协议,并且更新你的上传和请求调用。

创建一个 Swift 文件,点击 File\New\File…,然后在 iOS 下面选择 Swift 文件,点击下一步,文件命名为 ImaggaRouter.swift,然后点击创建。

在你新建的文件中添加下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import Foundation
import Alamofire

public enum ImaggaRouter: URLRequestConvertible {
static let baseURLPath = "http://api.imagga.com/v1"
static let authenticationToken = "Basic xxx"

case Content
case Tags(String)
case Colors(String)

public var URLRequest: NSMutableURLRequest {
let result: (path: String, method: Alamofire.Method, parameters: [String: AnyObject]) = {
switch self {
case .Content:
return ("/content", .POST, [String: AnyObject]())
case .Tags(let contentID):
let params = [ "content" : contentID ]
return ("/tagging", .GET, params)
case .Colors(let contentID):
let params = [ "content" : contentID, "extract_object_colors" : NSNumber(int: 0) ]
return ("/colors", .GET, params)
}
}()

let URL = NSURL(string: ImaggaRouter.baseURLPath)!
let URLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(result.path))
URLRequest.HTTPMethod = result.method.rawValue
URLRequest.setValue(ImaggaRouter.authenticationToken, forHTTPHeaderField: "Authorization")
URLRequest.timeoutInterval = NSTimeInterval(10 * 1000)

let encoding = Alamofire.ParameterEncoding.URL

return encoding.encode(URLRequest, parameters: result.parameters).0
}
}

Basic xxx替换为你自己的 token,设置好 URL 以及对应的参数。这个 router 会帮助我们创建 NSMutableURLRequest 实例,并且提公布了三种情况:.Content.Tags(String), 或 .Colors(String)。现在所有的模板代码都在这里,如果你需要更新它的话。返回 uploadImage(_:progress:completion:) 方法,并且把 Alamofire.upload 替换成下面的代码:

1
2
3
4
5
6
7
Alamofire.upload(
ImaggaRouter.Content,
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(data: imageData, name: "imagefile",
fileName: "image.jpg", mimeType: "image/jpeg")
},
/// original code continues...

然后替换 downloadTags(_:completion:) 方法里的 Alamofire.request

1
Alamofire.request(ImaggaRouter.Tags(contentID))

最后,更新 downloadColors(_:completion:) with 代码里的 Alamofire.request

1
Alamofire.request(ImaggaRouter.Colors(contentID))

最后一次编译运行,所有的功能都像之前一样,也就意味着没有破坏你的 app,进行了代码重构。不错的工作!

最终工程代码

下载地址

不要忘记替换你自己的 token。

你也可以去 github 下载 Alamofire

原帖地址

文章目录
  1. 1. 上篇地址
  2. 2. 获取数据
  3. 3. 优化 PhotoTagger
  4. 4. 最终工程代码
    1. 4.1. 下载地址
    2. 4.2. 原帖地址