iOS - Alamofire 网络请求

简介: 前言Alamofire 是 Swift 语言的 HTTP 网络开发工具包,相当于 Swift 实现 AFNetworking 版本。当然,AFNetworking 非常稳定,在 Mac OSX 与 iOS 中也能像其他 Objective-C 代码一样用 Swift 编写。

前言

  • Alamofire 是 Swift 语言的 HTTP 网络开发工具包,相当于 Swift 实现 AFNetworking 版本。当然,AFNetworking 非常稳定,在 Mac OSX 与 iOS 中也能像其他 Objective-C 代码一样用 Swift 编写。不过 Alamofire 更适合 Swift 语言风格习惯(Alamofire 与 AFNetworking 可以共存一个项目中,互不影响)。Alamofire 取名来源于 Alamo Fire flower。

  • Alamofire 的核心主要是试图简化 iOS 中 HTTP 网络连接,它通过使用 NSURLSession 以及 Foundation URL Loading System 来创建一个 Swift 本地的网络访问接口,从而实现令人难以置信效率的任务。

1、Alamofire

  • Alamofire 功能:

    • Chainable Request / Response methods
    • URL / JSON / plist Parameter Encoding
    • Upload File / Data / Stream
    • Download using Request or Resume data
    • Authentication with NSURLCredential
    • Progress Closure & NSProgress
    • cURL Debug Output
  • Alamofire 系统需求:

    Alamofire Version Minimum iOS Target Target Notes
    3.4.x iOS 8.0+ Xcode 7.3+ is required.
    3.1.4 -> 3.3.1 iOS 8.0+ Xcode 7.2+ is required.
    3.1.0 -> 3.1.3 iOS 8.0+ Xcode 7.1+ is required.
    2.0.0 -> 3.0.1 iOS 8.0+ Xcode 7.0+ is required.
    1.3.0 -> 1.3.1 iOS 7.0+ Xcode 6.4 is required.
    1.2.1 -> 1.2.3 iOS 7.0+ Xcode 6.3 is required.
    1.1.0 -> 1.2.0 iOS 7.0+ Xcode 6.1 is required.
    1.0.0 -> 1.0.1 iOS 7.0+ Xcode 6.0 is required. For Xcode 6.1, use the xcode-6.1 branch.
  • Alamofire 有许多让程序猿信服去使用它的理由。在 iOS 开发中,使用 NURLSession 是 HTTP 网络的未来趋势, 相比 NSURLConnection 来说,它的功能更加丰富:

    • 后台上传和下载
    • 暂停以及重新开始网络操作的能力
    • 可配置的容器(Container)
    • 子类和私有存储
    • 改进的认证处理
    • 对每个基础连接进行身份验证
    • 多种代理模式 -- NSURLConnection 拥有异步代码块的基本方法, 但是不能用它们的代理,NSURLSession 具有一种混合型的方法。
  • 对 AFNetworking 能做而 Alamofire 不能做的有以下几点:

    • UIKit 扩展
    • TLS 验证
    • NSOperation/NSURLConnection/AFURLConnectionOperation 调用
    • 多重 HTTP 网络请求构架

2、Alamofire 的添加

  • Github 网址:https://github.com/Alamofire/Alamofire

  • Alamofire 使用 ARC

  • Swift

        // 将第三方库文件复制到工程目录下
        Alamofire       
    
        // 将第三方库文件中的 xcodeproj 添加到工程中
        Alamofire.xcodeproj
    
        // 在 TARGETS -> General -> Embedded Binaries 下添加静态库文件(添加上边的)
        Alamofire.framework
    
        // 添加头文件
        import Alamofire

3、Alamofire 的设置

  • Swift

    • 请求超时时间设置

          // 必须设置为全局的
          var alamofireManager: Manager!
      
          let config = NSURLSessionConfiguration.defaultSessionConfiguration()
          config.timeoutIntervalForRequest = 5     // 秒
      
          self.alamofireManager = Manager(configuration: config)
          self.alamofireManager.request(.GET, "http://120.25.226.186:32812/video?type=JSON")
    • HTTP 方法(Medthods)

          Alamofire.Method enum 列表出在 RFC 2616 中定义的 HTTP 方法:
      
              public enum Method: String {
      
                  case OPTIONS = "OPTIONS"
                  case GET = "GET"
                  case HEAD = "HEAD"
                  case POST = "POST"
                  case PUT = "PUT"
                  case PATCH = "PATCH"
                  case DELETE = "DELETE"
                  case TRACE = "TRACE"
                  case CONNECT = "CONNECT"
              }
      
          这些值可以作为 Alamofire.request 请求的第一个参数。
      
          Alamofire.request(.POST, "https://httpbin.org/post")
      
          Alamofire.request(.PUT, "https://httpbin.org/put")
      
          Alamofire.request(.DELETE, "https://httpbin.org/delete")
    • 请求参数编码方式设置

          Alamofire 使用 Alamofire.ParameterEncoding 可以支持 URL query/URI form,JSON,PropertyList 方式编码参数。
      
          enum ParameterEncoding {
      
              case URL
              case URLEncodedInURL
              case JSON
              case PropertyList(NSPropertyListFormat, NSPropertyListWriteOptions)
              case Custom((URLRequestConvertible, [String : AnyObject]?) -> (NSMutableURLRequest, NSError?))
      
              public func encode(URLRequest: URLRequestConvertible, parameters: [String : AnyObject]?) -> (NSMutableURLRequest, NSError?)
              public func queryComponents(key: String, _ value: AnyObject) -> [(String, String)]
              public func escape(string: String) -> String
          }
      
          // URL 形式参数编码
      
              // 发送以下 HttpBody 内容: foo=bar&baz[]=a&baz[]=1&qux[x]=1&qux[y]=2&qux[z]=3
      
              let urlStr:URLStringConvertible = "https://httpbin.org/post"
              let parameters:[String: AnyObject]? = ["foo":"bar", "baz":["a", 1], "qux":["x":1, "y":2, "z":3]]
      
              Alamofire.request(.POST, urlStr, parameters: parameters)        // 默认编码方式是 URL
      
              Alamofire.request(.POST, urlStr, parameters: parameters, encoding: .URL)
      
          // JSON 形式参数编码
      
              // 发送以下 HttpBody 内容: {"foo":"bar", "baz":["a", 1], "qux":{"x":1, "y":2, "z":3}}
      
              let urlStr:URLStringConvertible = "https://httpbin.org/post"
              let parameters:[String: AnyObject]? = ["foo":"bar", "baz":["a", 1], "qux":["x":1, "y":2, "z":3]]
      
              Alamofire.request(.POST, urlStr, parameters: parameters, encoding:.JSON)                        
      
          // URLRequest 请求编码
      
              let url = NSURL(string: "https://httpbin.org/get")!
              var urlRequest = NSMutableURLRequest(URL: url)
      
              let param = ["foo": "bar"]
              let encoding = Alamofire.ParameterEncoding.URL
      
              (urlRequest, _) = encoding.encode(urlRequest, parameters: param)
    • 请求头设置

          let headers = ["User-Agent":"iPhone 6s Plus"]
      
          Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON", headers: headers)
      
          // 不设置时为默认值
          Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
    • 请求数据响应格式设置

          Built-in Response Methods:
      
              response()
              responseData()
              responseString(encoding:NSStringEncoding)
              responseJSON(options:NSJSONReadingOptions)
              responsePropertyList(options:NSPropertyListReadOptions)
      
          可以同时响应多种格式数据。
      
          // 响应 NSData 格式数据
      
              Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
                  .response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
      
                      /*
                          网络请求结束,成功时 error == nil。请求返回的数据存在 responseData 中,为 NSData 格式。
                      */  
                  }
      
          // 响应 String 格式数据
      
              Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
                  .responseString { (response:Response<String, NSError>) in
      
                      /*
                              网络请求结束,成功时 response.result.error == nil。请求返回的数据存在 response.result.value 中,为 String 格式。
                          或者成功时 response.result 的值为 .Success,失败时 response.result 的值为 .Failure。
                      */  
      
                      response.request     // original URL request
                      response.response    // URL response
                      response.data        // server data
                      response.result      // result of response serialization
      
                      // 获取并判断结果值
      
                      if let string = response.result.value {
      
                      } else {
      
                      }
      
                      // 判断结果值
      
                      if response.result.error == nil {
      
                      } else {
      
                      }
      
                      // 判断结果值
      
                      switch response.result {
      
                          case.Success(let value):
                          case.Failure(let error):
                      }
                  }
      
          // 响应 JSON 格式数据
      
              Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
                  .responseJSON { (response:Response<AnyObject, NSError>) in
      
                      /*
                          网络请求结束,成功时 response.result.error == nil。请求返回的数据存在 response.result.value 中,为 JSON 格式。
                          或者成功时 response.result 的值为 .Success,失败时 response.result 的值为 .Failure。
                      */  
                  }
      
          // 响应 PList 格式数据
      
              Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
                  .responsePropertyList { (response:Response<AnyObject, NSError>) in
      
                      /*
                          网络请求结束,成功时 response.result.error == nil。请求返回的数据存在 response.result.value 中,为 PList 格式。
                          或者成功时 response.result 的值为 .Success,失败时 response.result 的值为 .Failure。
                      */  
                  }
      
          // 响应 多种格式 数据
      
              Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
                  // 参数不使用时可以省略
                  .response { (_, _, responseData:NSData?, error:NSError?) in
      
                  }
      
                  .responseJSON { (response:Response<AnyObject, NSError>) in
      
                  }
    • Request 请求创建方式

          // Manager 方式
      
              // 必须设置为全局的
              var alamofireManager: Manager!
      
              self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
      
              self.alamofireManager.request(.GET, "http://120.25.226.186:32812/video?type=JSON")
      
          // Alamofire 方式,接收返回值
      
              let request = Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
          // 不接收返回值,request 不带参数
      
              Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
          // request 带参数
      
              Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video", parameters: ["type": "JSON"])
      
          // request 带参数及参数编码方式
      
              Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video", parameters: ["type": "JSON"], encoding: .URL)
      
          // request 带参数及请求头
      
              Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video", parameters: ["type": "JSON"], 
                                                                                     encoding: .URL, 
                                                                                      headers: ["User-Agent":"iPhone 6s"])
    • 请求任务创建方式

          // 数据请求 request (GET/POST)
      
              // Alamofire GET 方式
      
                  let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video?type=XML"
      
                  Alamofire.request(.GET, urlStr)
      
              // Alamofire POST 方式
      
                  let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video"
      
                  Alamofire.request(.GET, urlStr, parameters: ["type": "XML"])
      
              // Manager GET 方式
      
                  // 必须设置为全局的
                  var alamofireManager: Manager!
      
                  let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video?type=XML"
      
                  self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
      
                  self.alamofireManager.request(.GET, urlStr)
      
              // Manager POST 方式
      
                  // 必须设置为全局的
                  var alamofireManager: Manager!
      
                  let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video"
      
                  self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
      
                  self.alamofireManager.request(.GET, urlStr, parameters: ["type": "XML"])
      
          // 文件下载 download
      
              // 指定文件路径方式
      
                  Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4") 
                            { (temporaryURL:NSURL, response:NSHTTPURLResponse) -> NSURL in
      
                      /*
                              设置文件下载路径,temporaryURL 是沙盒下的文件临时存储路径,下载完成后会被自动删除。response.suggestedFilename 
                          为服务器端文件名。此 block 在子线程中执行。
                      */
      
                      return documentsDirUrl
                  }
      
                      .progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
      
                          /*
                              监听文件下载进度,此 block 在子线程中执行。
                          */
                      }
      
                      .response { (_, _, _, error:NSError?) in
      
                          /*
                              网络请求结束,成功时 error == nil。在 Swift 中文件已经存在时,再次相同路径写入会失败。
                          */
                      }
      
              // 使用默认提供的下载路径方式
      
                  Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4", destination: destination)
      
                      .progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
      
                          /*
                              监听文件下载进度,此 block 在子线程中执行。
                          */
                      }
      
                      .response { (_, _, _, error:NSError?) in
      
                          /*
                              网络请求结束,成功时 error == nil。在 Swift 中文件已经存在时,再次相同路径写入会失败。
                          */
                      }
      
              // 断点续传下载方式
      
                  let downloadRequest:Request = Alamofire.download(resumeData: resumeData, 
                                                                  destination: { (temporaryURL:NSURL, 
                                                                                      response:NSHTTPURLResponse) -> NSURL in
      
                      /*
                              设置文件下载路径,temporaryURL 是沙盒下的文件临时存储路径,下载完成后会被自动删除。response.suggestedFilename 
                          为服务器端文件名。此 block 在子线程中执行。
                      */
      
                      return documentsDirUrl
                  })
      
                      .progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
      
                          /*
                              监听文件下载进度,此 block 在子线程中执行。
                          */
                      }
      
                      .response { (_, _, data:NSData?, error:NSError?) in
      
                          /*
                              网络请求结束,成功时 error == nil。在 Swift 中文件已经存在时,再次相同路径写入会失败。
                          */
                      }
      
          // 文件上传 upload
      
              // Data 形式上传
      
                  Alamofire.upload(.POST, "http://192.168.88.200:8080/MJServer/upload", headers: headers, data: formBody)
      
                      .progress { (bytesLoad:Int64, totalBytesLoad:Int64, totalBytesExpectedToLoad:Int64) in
      
                          /*
                              监听文件上传进度,此 block 在子线程中执行。
                          */
                      }
      
                      .response { (_, _, responseData:NSData?, error:NSError?) in
      
                          /*
                              网络请求结束。
                          */
                      }
      
              // MultipartFormData 形式上传
      
                  Alamofire.upload(.POST, "http://192.168.88.200:8080/MJServer/upload", 
                                           multipartFormData: { (formData:MultipartFormData) in
      
                      /*
                          添加参数。第一个参数是需要添加的参数内容值,第二个是后台规定的参数名。
                          设置上传的文件。第一个参数是需要上传的文件路径,第二个是后台规定的参数名,第三个是上传后服务器端文件名称,第四个是文件类型。
                      */
      
                  }) { (encodingResult:Manager.MultipartFormDataEncodingResult) in
      
                      /*
                          数据编码完成。
                      */
      
                      switch encodingResult {
      
                      // 编码成功
                      case .Success(let uploadRequest, _, _):                                                                 
      
                          uploadRequest
      
                              .progress { (bytesLoad:Int64, totalBytesLoad:Int64, totalBytesExpectedToLoad:Int64) in
      
                                  /*
                                      监听文件上传进度,此 block 在子线程中执行。
                                  */
                              }
      
                              .response { (_, _, responseData:NSData?, error:NSError?) in
      
                                  /*
                                      网络请求结束。
                                  */
                              }
      
                      // 编码失败
                      case .Failure(let error):                                                                               
      
                          print(error)
                      }
                  }
    • 请求任务设置

          // 继续请求任务
          downloadRequest.resume()
      
          // 暂停请求任务
          downloadRequest.suspend()
      
          // 取消请求任务
          downloadRequest.cancel()
    • 文件下载设置

          // 设置文件下载路径
      
              let documentsDirUrl:NSURL = NSFileManager.defaultManager()
                                                       .URLsForDirectory( .DocumentDirectory, inDomains: .UserDomainMask)[0]
                                                       .URLByAppendingPathComponent(response.suggestedFilename!)
      
              if NSFileManager.defaultManager().fileExistsAtPath(documentsDirUrl.path!) {
      
                  // 移除已经存在的文件,在 Swift 中文件已经存在时,再次相同路径写入会失败
                  try! NSFileManager.defaultManager().removeItemAtURL(documentsDirUrl)
              }
      
          // 设置文件默认下载路径
      
              let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
      
          // 监听文件下载进度
      
              bytesWrite                  // 本次写入的大小
              totalBytesWrite             // 已经写入的大小
              totalBytesExpectedToWrite   // 总大小
      
              // 设置下载进度条
              let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
              self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), withObject: progressNum, waitUntilDone: true)
    • 文件上传设置

          // Data 形式上传
      
              let boundary = "myBoundary"
      
              // 设置请求头
              /*
                  upload task 不会在请求头里添加 content-type (上传数据类型)字段,@"myBoundary" 为请求体边界,参数可以随便设置,但需一致
              */
              let headers = ["Content-Type":"multipart/form-data; charset=utf-8; boundary=\(boundary)"]
      
              // 设置请求文件参数
      
                  let formBody = NSMutableData()
      
                  // 参数开始分割线
                  /*
                      每个参数开始前都需要加
                  */
                  formBody.appendData("--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!)
                  formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
                  // 参数
                  formBody.appendData("Content-Disposition: form-data; name=\"\("username")\"\r\n\r\n\("jhq")"
                          .dataUsingEncoding(NSUTF8StringEncoding)!)
      
                  // username 是后台规定的参数名,jhq 是需要添加的参数内容值
                  formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
                  // 文件开始分割线
                  /*
                      每个文件开始前都需要加
                  */
                  formBody.appendData("--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!)
                  formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
                  // 文件参数名
                  formBody.appendData("Content-Disposition: form-data; name=\"\("file")\"; filename=\"\("test.mp4")\""
                          .dataUsingEncoding(NSUTF8StringEncoding)!)
      
                  // file 是后台规定的参数名,test.mp4 为上传后服务器端文件名称
                  formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)                            
      
                  // 文件的类型
                  formBody.appendData("Content-Type: mp4".dataUsingEncoding(NSUTF8StringEncoding)!)
                  formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
                  formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
                  // 待上传文件数据
                  /*
                      本地待上传的文件路径
                  */
                  formBody.appendData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("minion", ofType: "mp4")!)!)
                  formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
                  // 结束分割线标记
                  formBody.appendData("--\(boundary)--".dataUsingEncoding(NSUTF8StringEncoding)!)
                  formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
          // 指定文件路径形式上传
          /*
              public func appendBodyPart(fileURL fileURL: NSURL, name: String, fileName: String, mimeType: String);
      
              第一个参数是需要上传的文件路径,第二个是后台规定的参数名,第三个是上传后服务器端文件名称,第四个是文件类型。
          */
          let fileUrl = NSBundle.mainBundle().URLForResource("HQ_0005", withExtension: "jpg")!
          formData.appendBodyPart(fileURL: fileUrl, name: "file", fileName: "test.png", mimeType: "image/jpeg")
      
          // 指定文件数据形式上传
          /*
              public func appendBodyPart(data data: NSData, name: String, fileName: String, mimeType: String);
      
              第一个参数是需要上传的文件数据,第二个是后台规定的参数名,第三个是上传后服务器端文件名称,第四个是文件类型。
          */
          let fileData = NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("minion", ofType: "mp4")!)
          formData.appendBodyPart(data: fileData!, name: "file", fileName: "test.mp4", mimeType: "mp4")
      
          // 添加参数
          /*
              public func appendBodyPart(data data: NSData, name: String);
      
              第一个参数是需要添加的参数内容值,第二个是后台规定的参数名。
          */
          formData.appendBodyPart(data: "jhq".dataUsingEncoding(NSUTF8StringEncoding)!, name: "username")
      
          // 监听文件上传进度
      
          bytesLoad                   // 本次写入的大小
          totalBytesLoad              // 已经写入的大小
          totalBytesExpectedToLoad    // 总大小
      
          let progressNum1:NSNumber = NSNumber(float: Float(Double(totalBytesLoad)/Double(totalBytesExpectedToLoad)))
          self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), withObject: progressNum1, waitUntilDone: true)

4、Alamofire HTTP 认证

  • 支持以下几种认证:

    • HTTP Basic
    • HTTP Digest
    • Kerberos
    • NTLM
  • Swift

        // Http basic 方式认证
    
            let user = "user"
            let password = "password"
    
            Alamofire.request(.GET, "https://httpbin.org/basic-auth/\(user)/\(password)")
    
                .authenticate(user: user, password: password)
    
        // NSURLCredential 方式认证
    
            let user = "user"
            let password = "password"
    
            let credential = NSURLCredential(user: user, password: password, persistence: .ForSession)
    
            Alamofire.request(.GET, "https://httpbin.org/basic-auth/\(user)/\(password)")
    
                .authenticate(usingCredential: credential)
    
        // headers 方式认证
    
            let user = "user"
            let password = "password"
    
            let credentialData = "\(user):\(password)".dataUsingEncoding(NSUTF8StringEncoding)!
            let base64Credentials = credentialData.base64EncodedStringWithOptions([])
    
            let headers = ["Authorization": "Basic \(base64Credentials)"]
    
            Alamofire.request(.GET, "https://httpbin.org/basic-auth/user/password", headers: headers)

5、Alamofire HTTP 响应状态信息识别

  • Swift

    • 手动识别

          /*
                  Alamofire 还提供了 HTTP 响应状态的判断识别,通过 validate 方法,对于在我们期望之外的 HTTP 响应状态信息,
              Alamofire 会提供报错信息:
          */
      
          Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
      
              .validate(statusCode: 200..<300)
      
              .validate(contentType: ["application/json"])
    • 自动识别

          // validate 方法还提供自动识别机制,我们调用 validate 方法时不传入任何参数,则会自动认为 200…299 的状态吗为正常:
      
          Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
      
              .validate()

6、Alamofire Timeline

  • Swift

        /*
                Alamofire collects timings throughout the lifecycle of a Request and creates a Timeline object 
            exposed as a property on a Response.
        */
    
        Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video", parameters: ["type": "JSON"])
    
            .validate()
    
            .responseJSON { response in
    
            print(response.timeline)
        }
    
        The above reports the following Timeline info:
    
            Latency: 0.428 seconds
            Request Duration: 0.428 seconds
            Serialization Duration: 0.001 seconds
            Total Duration: 0.429 seconds

7、Alamofire 调试打印

  • Swift

        // GET print
    
            let request = Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
    
            print(request)
    
            // 打印输出 GET http://192.168.88.200:8080/MJServer/video?type=JSON
    
        // POST print
    
            let request = Alamofire.request(.POST, "http://192.168.88.200:8080/MJServer/video", parameters: ["type":"JSON"])
    
            print(request)
    
            // 打印输出 POST http://192.168.88.200:8080/MJServer/video
    
        // GET debugprint
    
            let request = Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
    
            debugPrint(request)
    
            // 打印输出 curl 信息
    
            $ curl -i \
                -H "User-Agent: SwiftAlamofire/com.qianqianstudio.SwiftAlamofire (1; OS Version 9.3 (Build 13E230))" \
                -H "Accept-Language: zh-Hans-US;q=1.0, en-US;q=0.9" \
                -H "Accept-Encoding: gzip;q=1.0, compress;q=0.5" \
                    "http://192.168.88.200:8080/MJServer/video?type=JSON"

8、Alamofire 网络连接状态检查

  • Swift

        网络连接状态:
    
            public enum NetworkReachabilityStatus {
                case Unknown            网络状态未知
                case NotReachable       无网络连接
                case Reachable(Alamofire.NetworkReachabilityManager.ConnectionType)
            }
    
            public enum ConnectionType {
                case EthernetOrWiFi     WiFi 网络
                case WWAN               无线网络(蜂窝移动网络)
            }
    
        let manager = NetworkReachabilityManager()
    
        // 监听网络状态闭包
        manager?.listener = { status in
    
            /*
                开启网络状态监听后,只要网络状态发生改变就会调用该闭包代码段。
            */
    
            print("Network Status Changed: \(status)")
        }
    
        // 开启监听网络状态
        manager?.startListening()
    
        // 关闭网络状态监听
        manager?.stopListening()
    
        // 获取网络连接状态
        let status = manager?.networkReachabilityStatus
    
        // 判断网络是否连接
        let isReachable:Bool? = manager?.isReachable
    
        // 判断 WiFi 是否连接
        let isReachableOnEthernetOrWiFi:Bool? = manager?.isReachableOnEthernetOrWiFi
    
        // 判断 无线网络 是否连接
        let isReachableOnWWAN:Bool? = manager?.isReachableOnWWAN

9、Alamofire 异步 GET 数据请求

  • Swift

        // Alamofire 方式
    
            let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video?type=XML"
    
            Alamofire.request(.GET, urlStr)
    
                .response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
    
                    /*
                        网络请求结束,成功时 error == nil。请求返回的数据存在 responseData 中,为 NSData 格式。
                    */
                }
    
        // Manager 方式
    
            // 必须设置为全局的
            var alamofireManager: Manager!
    
            let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video?type=XML"
    
            self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
    
            self.alamofireManager.request(.GET, urlStr)
    
                .response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
    
                    /*
                        网络请求结束,成功时 error == nil。请求返回的数据存在 responseData 中,为 NSData 格式。
                    */
                }

10、Alamofire 文件下载

  • 支持的类型:

    • Request
    • Resume Data
  • 默认支持后台方式下载

  • Swift

    • 指定文件路径方式

          // 目标路径闭包展开
      
          Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4") 
                            { (temporaryURL:NSURL, response:NSHTTPURLResponse) -> NSURL in
      
              /*
                      设置文件下载路径,temporaryURL 是沙盒下的文件临时存储路径,下载完成后会被自动删除。response.suggestedFilename 
                  为服务器端文件名。此 block 在子线程中执行。
              */
      
              let documentsDirUrl:NSURL = NSFileManager.defaultManager()
                                                       .URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
                                                       .URLByAppendingPathComponent(response.suggestedFilename!)
      
              if NSFileManager.defaultManager().fileExistsAtPath(documentsDirUrl.path!) {
      
                  // 移除已经存在的文件,在 Swift 中文件已经存在时,再次相同路径写入会失败
                  try! NSFileManager.defaultManager().removeItemAtURL(documentsDirUrl)                
              }   
      
              return documentsDirUrl
          }
      
              .progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
      
                  /*
                      监听文件下载进度,此 block 在子线程中执行。
                  */
      
                  // 设置下载进度条 
                  let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
                  self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), withObject: progressNum, waitUntilDone: true)
              }
      
              .response { (_, _, _, error:NSError?) in
      
                  /*
                      网络请求结束,成功时 error == nil。在 Swift 中文件已经存在时,再次相同路径写入会失败。
                  */  
              }
    • 使用默认提供的下载路径方式

          // 目标路径闭包
      
              // 设置文件的默认下载路径
              let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
      
              Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4", destination: destination)
      
                  .progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
      
                      /*
                          监听文件下载进度,此 block 在子线程中执行。
                      */
      
                      // 设置下载进度条
                      let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
                      self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), 
                                            withObject: progressNum, 
                                         waitUntilDone: true)
                  }
      
                  .response { (_, _, _, error:NSError?) in
      
                      /*
                          网络请求结束,成功时 error == nil。在 Swift 中文件已经存在时,再次相同路径写入会失败。
                      */
                  }
    • 断点续传下载方式

          // 使用断点下载需要之前下载的临时文件存在,才能继续下载。
      
          var downloadRequest:Request!
          var resumeData:NSData!
      
          // 开始下载
      
              let resumeTmpPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, .UserDomainMask, true)[0] + "/resumeData.tmp"
      
              // 判断断点保存的文件是否存在
              if NSFileManager.defaultManager().fileExistsAtPath(resumeTmpPath) {
      
                  // 断点开始下载
      
                  // 读取断点保存的数据
                  self.resumeData = NSData(contentsOfFile: resumeTmpPath)
      
                  self.downloadRequest = Alamofire.download(resumeData: self.resumeData, destination: 
                                                   { (temporaryURL:NSURL, response:NSHTTPURLResponse) -> NSURL in
      
                  let documentsDirUrl:NSURL = NSFileManager.defaultManager()
                                                           .URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
                                                           .URLByAppendingPathComponent(response.suggestedFilename!)                   
                      if NSFileManager.defaultManager().fileExistsAtPath(documentsDirUrl.path!) {
      
                          try! NSFileManager.defaultManager().removeItemAtURL(documentsDirUrl)
                      }
      
                      return documentsDirUrl
                  })
      
                  .progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
      
                      let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
                      self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), 
                                            withObject: progressNum, 
                                         waitUntilDone: true)
                      }
      
                      .response { (_, _, data:NSData?, error:NSError?) in
      
                      if error == nil {
      
                          // 删除断点下载缓存文件
      
                          let resumeTmpPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, 
                                                                                  .UserDomainMask, 
                                                                                  true)[0] 
                                                                                + "/resumeData.tmp"
      
                          if NSFileManager.defaultManager().fileExistsAtPath(resumeTmpPath) {
                              try! NSFileManager.defaultManager().removeItemAtPath(resumeTmpPath)
                          }
      
                      } else {
      
                          // 下载的临时文件不存在处理
      
                          if error?.localizedFailureReason == "No such file or directory" {
      
                                  let resumeTmpPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, 
                                                                                          .UserDomainMask, 
                                                                                          true)[0]
                                                                                        + "/resumeData.tmp"
      
                                  if NSFileManager.defaultManager().fileExistsAtPath(resumeTmpPath) {
      
                                      // 删除断点下载缓存文件,否则继续断点下载会报错
                                      try! NSFileManager.defaultManager().removeItemAtPath(resumeTmpPath)
                                  }   
                              }
                          }
                      }
              } else {
      
                  // 重新开始下载
      
                  self.resumeData = NSData()
      
                  self.downloadRequest = Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4") 
                                                           { (temporaryURL:NSURL, response: NSHTTPURLResponse) -> NSURL in
      
                      let documentsDirUrl:NSURL = NSFileManager.defaultManager()
                                                               .URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
                                                               .URLByAppendingPathComponent(response.suggestedFilename!)
      
                          if NSFileManager.defaultManager().fileExistsAtPath(documentsDirUrl.path!) {
      
                              try! NSFileManager.defaultManager().removeItemAtURL(documentsDirUrl)
                          }
      
                          return documentsDirUrl
                  }
      
                      .progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
      
                          let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
                          self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), 
                                                withObject: progressNum, 
                                             waitUntilDone: true)
                      }
      
                      .response { (_, _, data:NSData?, error:NSError?) in
      
                          if error == nil {
      
                          } else {
      
                              // 停止下载处理
      
                              if error!.code == NSURLErrorCancelled {
      
                                  if data != nil {
      
                                      // 意外终止的话,把已下载的数据储存起来
                                      self.resumeData = data
      
                                      let resumeTmpPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, 
                                                                                              .UserDomainMask, 
                                                                                              true)[0] 
                                                                                            + "/resumeData.tmp"
      
                                      self.resumeData.writeToFile(resumeTmpPath, atomically: true)
                                  }
      
                              } else {
      
                          }
                      }
                  }
              }
      
          // 暂停下载
      
              self.downloadRequest.suspend()
      
          // 继续下载
      
              self.downloadRequest.resume()
      
          // 停止下载
      
              self.downloadRequest.cancel()

11、Alamofire 异步 POST 数据请求

  • Swift

    • Alamofire 方式

          let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video"
          let parameters:[String: AnyObject]? = ["type":"XML"]
      
          Alamofire.request(.POST, urlStr, parameters: parameters)
      
              .response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
      
                  /*
                      网络请求结束,成功时 error == nil。请求返回的数据存在 responseData 中,为 NSData 格式。
                  */  
              }
    • Manager 方式

          // 必须设置为全局的
          var alamofireManager: Manager!
      
          let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video"
          let parameters:[String: AnyObject]? = ["type":"XML"]
      
          self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
      
          self.alamofireManager.request(.POST, urlStr, parameters: parameters)
      
              .response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
      
                  /*
                      网络请求结束,成功时 error == nil。请求返回的数据存在 responseData 中,为 NSData 格式。
                  */  
              }

12、Alamofire 文件上传

  • 支持的类型:

    • File
    • Data
    • Stream
    • MultipartFormData
  • Swift

    • Data 形式上传

          let boundary = "myBoundary"
      
          // 设置请求头
          /*
              upload task 不会在请求头里添加 content-type (上传数据类型)字段,@"myBoundary" 为请求体边界,参数可以随便设置,但需一致
          */
          let headers = ["Content-Type":"multipart/form-data; charset=utf-8; boundary=\(boundary)"]
      
          // 设置请求文件参数
      
              let formBody = NSMutableData()
      
              // 参数开始分割线
              /*
                  每个参数开始前都需要加
              */
              formBody.appendData("--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!)
              formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
              // 参数
              /*
                  username 是后台规定的参数名,jhq 是需要添加的参数内容值
              */
              formBody.appendData("Content-Disposition: form-data; name=\"\("username")\"\r\n\r\n\("jhq")"
                      .dataUsingEncoding(NSUTF8StringEncoding)!)
              formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
              // 文件开始分割线
              /*
                  每个文件开始前都需要加
              */
              formBody.appendData("--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!)
              formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
              // 文件参数名
              /*
                  file 是后台规定的参数名,test.mp4 为上传后服务器端文件名称
              */
              formBody.appendData("Content-Disposition: form-data; name=\"\("file")\"; filename=\"\("test.mp4")\""
                      .dataUsingEncoding(NSUTF8StringEncoding)!)
              formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
              // 文件的类型
              formBody.appendData("Content-Type: mp4".dataUsingEncoding(NSUTF8StringEncoding)!)
              formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
              formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
              // 待上传文件数据
              /*
                  本地待上传的文件路径
              */
              formBody.appendData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("minion", ofType: "mp4")!)!)
              formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
              // 结束分割线标记
              formBody.appendData("--\(boundary)--".dataUsingEncoding(NSUTF8StringEncoding)!)
              formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
          Alamofire.upload(.POST, "http://192.168.88.200:8080/MJServer/upload", headers: headers, data: formBody)
      
              .progress { (bytesLoad:Int64, totalBytesLoad:Int64, totalBytesExpectedToLoad:Int64) in
      
                  /*
                      监听文件上传进度,此 block 在子线程中执行。
                  */
      
                  let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesLoad)/Double(totalBytesExpectedToLoad)))
                  self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), withObject: progressNum, waitUntilDone: true)
              }
      
              .response { (_, _, responseData:NSData?, error:NSError?) in
      
                  /*
                      网络请求结束。
                  */  
              }
    • MultipartFormData 形式上传

          Alamofire.upload(.POST, "http://192.168.88.200:8080/MJServer/upload", 
                                  multipartFormData: { (formData:MultipartFormData) in
      
              /*
                  添加参数。第一个参数是需要添加的参数内容值,第二个是后台规定的参数名。
      
                  设置上传的文件。第一个参数是需要上传的文件路径,第二个是后台规定的参数名,第三个是上传后服务器端文件名称,第四个是文件类型。
              */
      
              // 添加参数
      
                  formData.appendBodyPart(data: "jhq".dataUsingEncoding(NSUTF8StringEncoding)!, name: "username")
      
              // 指定文件路径形式上传
      
                  let fileUrl = NSBundle.mainBundle().URLForResource("HQ_0005", withExtension: "jpg")!
      
                  formData.appendBodyPart(fileURL: fileUrl, name: "file", fileName: "test.png", mimeType: "image/jpeg")
      
              // 指定文件数据形式上传
      
                  let fileData = NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("minion", ofType: "mp4")!)
      
                  formData.appendBodyPart(data: fileData!, name: "file", fileName: "test.mp4", mimeType: "mp4")
      
          }) { (encodingResult:Manager.MultipartFormDataEncodingResult) in
      
              /*
                  数据编码完成。
              */
      
              switch encodingResult {
      
                  // 编码成功
                  case .Success(let uploadRequest, _, _):
      
                      uploadRequest
      
                          .progress { (bytesLoad:Int64, totalBytesLoad:Int64, totalBytesExpectedToLoad:Int64) in
      
                          /*
                              监听文件上传进度,此 block 在子线程中执行。
                          */
      
                          let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesLoad)/Double(totalBytesExpectedToLoad)))
                          self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), 
                                                withObject: progressNum, 
                                             waitUntilDone: true)
                      }
      
                      .response { (_, _, responseData:NSData?, error:NSError?) in
      
                          /*
                              网络请求结束。
                          */  
                      }
      
                  // 编码失败
                  case .Failure(let error):
      
                      print(error)
              }
          }
目录
相关文章
|
3月前
|
XML JSON API
IOS网络编程:介绍一下 Alamofire 库。
IOS网络编程:介绍一下 Alamofire 库。
37 3
|
Swift 数据安全/隐私保护 iOS开发
iOS开发 - swift通过Alamofire实现https通信
iOS开发 - swift通过Alamofire实现https通信
345 0
iOS开发 - swift通过Alamofire实现https通信
|
存储 iOS开发
iOS网络请求小知识: get 和post 布尔值参数处理
iOS网络请求小知识: get 和post 布尔值参数处理
808 0
iOS网络请求小知识: get 和post 布尔值参数处理
|
XML JSON JavaScript
iOS网络请求指南: 请求参数的拼接(签名)、返回参数解析(JSON/XML解析)、案例(条码支付综合前置平台申请退款)
iOS网络请求指南: 请求参数的拼接(签名)、返回参数解析(JSON/XML解析)、案例(条码支付综合前置平台申请退款)
355 0
iOS网络请求指南: 请求参数的拼接(签名)、返回参数解析(JSON/XML解析)、案例(条码支付综合前置平台申请退款)
|
XML 存储 JSON
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求(四)
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求
222 0
|
安全 网络安全 Android开发
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求(三)
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求
436 0
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求(三)
|
Web App开发 存储 前端开发
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求(二)
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求
163 0
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求(二)
|
Web App开发 安全 网络协议
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求(一)
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求
169 0
深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求(一)