Alamofire 上传图片入门教程(下)

上篇地址

获取数据

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

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中的代码:

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

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

Imagga-Tagging-Response.png

你不用关心 confidence 的分数,在本次教程中我们只使用 tag 的名称。
下一步,返回 downloadTags(_: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: 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
PhotoTagger-tags.png

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

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 的情况,添加下面的代码:

self.downloadTags(firstFileID) { tags in
  self.downloadColors(firstFileID) { colors in
    completion(tags: tags, colors: colors)
  }
}

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


PhotoTagger-colors.png
PhotoTagger-colors.png

优化 PhotoTagger

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

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

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

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

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 替换成下面的代码:

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

Alamofire.request(ImaggaRouter.Tags(contentID))

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

Alamofire.request(ImaggaRouter.Colors(contentID))

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

最终工程代码

下载地址

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

你也可以去 github 下载 Alamofire

原帖地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容