Alamofire 是 Swift 語言的 HTTP 網絡開發工具包,至關於 Swift 實現 AFNetworking 版本。固然,AFNetworking 很是穩定,在 Mac OSX 與 iOS 中也能像其餘 Objective-C 代碼同樣用 Swift 編寫。不過 Alamofire 更適合 Swift 語言風格習慣(Alamofire 與 AFNetworking 能夠共存一個項目中,互不影響)。Alamofire 取名來源於 Alamo Fire flower。git
Alamofire 的核心主要是試圖簡化 iOS 中 HTTP 網絡鏈接,它經過使用 NSURLSession 以及 Foundation URL Loading System 來建立一個 Swift 本地的網絡訪問接口,從而實現使人難以置信效率的任務。github
Alamofire 功能:json
Alamofire 系統需求:xcode
Alamofire Version | Minimum iOS Target | Target Notes
------------------------|--------------------------|-------------------------------------------------------------------
3.4.x | iOS 8.0+ | Xcode 7.3+ is required.
3.1.4 -> 3.3.1 | iOS 8.0+ | Xcode 7.2+ is required.
3.1.0 -> 3.1.3 | iOS 8.0+ | Xcode 7.1+ is required.
2.0.0 -> 3.0.1 | iOS 8.0+ | Xcode 7.0+ is required.
1.3.0 -> 1.3.1 | iOS 7.0+ | Xcode 6.4 is required.
1.2.1 -> 1.2.3 | iOS 7.0+ | Xcode 6.3 is required.
1.1.0 -> 1.2.0 | iOS 7.0+ | Xcode 6.1 is required.
1.0.0 -> 1.0.1 | iOS 7.0+ | Xcode 6.0 is required. For Xcode 6.1, use the xcode-6.1 branch.緩存
Alamofire 有許多讓程序猿信服去使用它的理由。在 iOS 開發中,使用 NURLSession 是 HTTP 網絡的將來趨勢, 相比 NSURLConnection 來講,它的功能更加豐富:服務器
對 AFNetworking 能作而 Alamofire 不能作的有如下幾點:網絡
Github 網址:https://github.com/Alamofire/Alamofire閉包
Alamofire 使用 ARCapp
Swiftdom
// 將第三方庫文件複製到工程目錄下 Alamofire // 將第三方庫文件中的 xcodeproj 添加到工程中 Alamofire.xcodeproj // 在 TARGETS -> General -> Embedded Binaries 下添加靜態庫文件(添加上邊的) Alamofire.framework // 添加頭文件 import 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)
支持如下幾種認證:
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)
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()
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
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"
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
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 格式。 */ }
支持的類型:
默認支持後臺方式下載
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()
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 格式。 */ }
支持的類型:
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) } }