iOS - Alamofire 網絡請求

前言

  • Alamofire 是 Swift 語言的 HTTP 網絡開發工具包,至關於 Swift 實現 AFNetworking 版本。固然,AFNetworking 很是穩定,在 Mac OSX 與 iOS 中也能像其餘 Objective-C 代碼同樣用 Swift 編寫。不過 Alamofire 更適合 Swift 語言風格習慣(Alamofire 與 AFNetworking 能夠共存一個項目中,互不影響)。Alamofire 取名來源於 Alamo Fire flower。git

  • Alamofire 的核心主要是試圖簡化 iOS 中 HTTP 網絡鏈接,它經過使用 NSURLSession 以及 Foundation URL Loading System 來建立一個 Swift 本地的網絡訪問接口,從而實現使人難以置信效率的任務。github

一、Alamofire

  • Alamofire 功能:json

    • 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 系統需求:xcode

    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 網絡請求構架

二、Alamofire 的添加

  • Github 網址:https://github.com/Alamofire/Alamofire閉包

  • Alamofire 使用 ARCapp

  • Swiftdom

    // 將第三方庫文件複製到工程目錄下
        Alamofire       
    
        // 將第三方庫文件中的 xcodeproj 添加到工程中
        Alamofire.xcodeproj
    
        // 在 TARGETS -> General -> Embedded Binaries 下添加靜態庫文件(添加上邊的)
        Alamofire.framework
    
        // 添加頭文件
        import Alamofire

三、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)

四、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)

五、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()

六、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

七、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"

八、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

九、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 格式。
                    */
                }

十、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()

十一、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 格式。
                  */  
              }

十二、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)
              }
          }
相關文章
相關標籤/搜索