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

作者: hrscy | 来源:发表于2016-07-19 10:45 被阅读370次

    上篇地址

    获取数据

    在 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.pngPhotoTagger-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.pngPhotoTagger-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

    原帖地址

    相关文章

      网友评论

        本文标题:Alamofire 上传图片入门教程(下)

        本文链接:https://www.haomeiwen.com/subject/wckmjttx.html