前言
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)
}
}
-