iOS - Alamofire 网络请求
前言
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)
}
}
iOS - Alamofire 网络请求的更多相关文章
- ios htttp网络请求cookie的读取与写入(NSHTTPCookieStorage)
当你访问一个网站时,NSURLRequest都会帮你主动记录下来你访问的站点设置的Cookie,如果 Cookie 存在的话,会把这些信息放在 NSHTTPCookieStorage 容器中共享,当你 ...
- iOS开发网络请求——大文件的多线程断点下载
iOS开发中网络请求技术已经是移动app必备技术,而网络中文件传输就是其中重点了.网络文件传输对移动客户端而言主要分为文件的上传和下载.作为开发者从技术角度会将文件分为小文件和大文件.小文件因为文件大 ...
- iOS - AFNetworking 网络请求
前言 在 iOS 开发中,一般情况下,简单的向某个 Web 站点简单的页面提交请求并获取服务器的响应,用 Xcode 自带的 NSURLConnection 是能胜任的.但是,在绝大部分下我们所需要访 ...
- iOS - ASIHTTPRequest 网络请求
前言 使用 iOS SDK 中的 HTTP 网络请求 API,相当的复杂,调用很繁琐,ASIHTTPRequest 就是一个对 CFNetwork API 进行了封装,并且使用起来非常简单的一套 AP ...
- iOS - NSURLSession 网络请求
前言 NS_CLASS_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0) @interface NSURLSession : NSObject @available(iOS ...
- iOS - NSURLConnection 网络请求
前言 @interface NSURLConnection : NSObject class NSURLConnection : NSObject DEPRECATED: The NSURLConne ...
- iOS之网络请求NSURLSession剖析
2013年的WWDC大会上,苹果推出了NSURLSession,对Foundation URL加载系统进行了彻底的重构,提供了更丰富的API来处理网络请求,如:支持http2.0协议.直接把数据下载到 ...
- iOS之网络请求及各类错误代码含义总结(包含AFN错误码大全)
转自http://blog.csdn.net/wangyanchang21/article/details/50932191 在很多时候都会遇到错误, 还会带有一些 Error Code , 比如在各 ...
- iOS 多网络请求同步并发
iOS中经常会用到多线程,在多线程中有一个线程组的概念(group),创建多个线程组任务,多组任务都完成之后,就会进入dispatch_group_notify队列中. 同时多线程中还有一个信号量的概 ...
随机推荐
- PHP程序中删除字符串最后一个字符的三种方法
常见的语法格式: foreach ($arr as $key => $value) {$arr_str = $arr['x_id'] . ',' . $arr_str;} 假设字符数组 $arr ...
- 一道面试题比较synchronized和读写锁
一.科普定义 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步关键字相信大家都用得比较多,在上一篇“多个线程之间共享数据的方式”中也详细列举他的应用, ...
- Android动画之Interpolator和AnimationSet
AnimationSet可以加入Animation,加入之后设置AnimationSet对加入的所有Animation都有效. AnimationSet anim=new AnimationSet(t ...
- c#中的委托和事件(转)
引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去 ...
- 【20160924】GOCVHelper MFC增强算法(3)
//获得当前目录路径 static CString GetLocalPath(){ CString csCfgFilePath; GetModuleFi ...
- 《Effective C++》读书摘要
http://www.cnblogs.com/fanzhidongyzby/archive/2012/11/18/2775603.html 1.让自己习惯C++ 条款01:视C++为一个语言联邦 条款 ...
- Poj(1273),最大流,EK
Drainage Ditches Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 69355 Accepted: 2687 ...
- oracle闪回查询
一.引言 程序中用到需要同步oracle更新和删除数据,于是考虑利用oracle的闪回查询机制来实现. 利用该机制首先需要oracle启用撤销表空间自动管理回滚信息,并根据实际情况设置对数据保存的有效 ...
- 使用Keil的MicroLIB时自动设置堆大小——玩嵌入式以来最高难度
Keil编译项目,如果使用微库MicroLIB,就可以使用malloc.微库内部位置一个堆管理模块.芯片的RAM大小是固定了的,前面分为全局变量,后面分给堆和栈,这是一般开发方式.但是我们在开发项目的 ...
- uva 10090 Marbles
Problem F Marbles Input: standard input Output: standard output I have some (say, n) marbles (small ...