iOS - Alamofire 网络请求

时间:2021-09-12 21:38:56

前言

  • 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)
      }
      }