Alamofire: элегантная работа с сетью на Swift
Alamofire — это библиотека для работы с HTTP-сетью, написанная на языке Swift. Создана автором библиотеки AFNetworking.
Для Xcode 6.1 используйте ветку
xcode-6.1
.
Из-за отсутствия надлежащей инфраструктуры для управления зависимостями Swift использование Alamofire в вашем проекте требует выполнения следующих шагов:
git submodule add https://github.com/Alamofire/Alamofire.git
.Alamofire
и перетащите Alamofire.xcodeproj
в навигатор файлов вашего проекта приложения.Alamofire.framework
.+
в левом верхнем углу панели и выберите «Новая фаза копирования файлов». Переименуйте эту новую фазу в «Копировать фреймворки», установите «Назначение» в «Фреймворки» и добавьте Alamofire.framework
.import Alamofire
Alamofire.request(.GET, "http://httpbin.org/get")
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
.response { (request, response, data, error) in
println(request)
println(response)
println(error)
}
Работа с сетью в Alamofire выполняется асинхронно. Асинхронное программирование может быть источником разочарования для программистов, незнакомых с этой концепцией, но существуют очень веские причины для такого подхода.
Вместо блокировки выполнения для ожидания ответа от сервера указывается обратный вызов для обработки ответа после его получения. Результат запроса доступен только в области обработчика ответов. Любое выполнение, зависящее от ответа или данных, полученных от сервера, должно выполняться внутри обработчика.
Встроенные методы ответа
response()
;responseString(encoding: NSStringEncoding)
;responseJSON(options: NSJSONReadingOptions)
;responsePropertyList(options: NSPropertyListReadOptions)
.Alamofire.request(.GET, "http://httpbin.org/get")
.responseString { (_, _, string, _) in
println(string)
}
Alamofire.request(.GET, "http://httpbin.org/get")
.responseJSON { (_, _, JSON, _) in
println(JSON)
} **Ответ:**
#### Chained Response Handlers
Обработчики ответов могут быть связаны:
```swift
Alamofire.request(.GET, "http://httpbin.org/get")
.responseString { (_, _, string, _) in
println(string)
}
.responseJSON { (_, _, JSON, _) в
println(JSON)
}
Alamofire.Method
перечисляет HTTP-методы, определённые в RFC 7231 §4.3:
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, "http://httpbin.org/post")
Alamofire.request(.PUT, "http://httpbin.org/put")
Alamofire.request(.DELETE, "http://httpbin.org/delete")
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
// http://httpbin.org/get?foo=bar
let parameters = [
"foo": "bar",
"baz": ["a", 1],
"qux": [
"x": 1,
"y": 2,
"z": 3
]
]
Alamofire.request(.POST, "http://httpbin.org/post", parameters: parameters)
// HTTP body: foo=bar&baz[]=a&baz[]=1&qux[x]=1&qux[y]=2&qux[z]=3
Параметры также можно кодировать как JSON, список свойств или любой другой пользовательский формат, используя перечисление ParameterEncoding
:
enum ParameterEncoding {
case URL
case JSON
case PropertyList(format: NSPropertyListFormat,
options: NSPropertyListWriteOptions)
func encode(request: NSURLRequest,
parameters: [String: AnyObject]?) ->
(NSURLRequest, NSError?)
{ ... }
}
URL
: строка запроса, которая будет установлена или добавлена к любому существующему запросу URL для запросов GET
, HEAD
и DELETE
, или установлена в качестве тела для запросов с любым другим HTTP-методом. Поле HTTP-заголовка Content-Type
для кодированного запроса с телом HTTP установлено на application/x-www-form-urlencoded
. Поскольку не существует опубликованной спецификации о том, как кодировать типы коллекций, используется соглашение о добавлении []
к значению ключа для массивов (foo[]=1&foo[]=2
), и добавлении ключа, заключённого в квадратные скобки, для вложенных значений словаря (foo[bar]=baz
).
JSON
: использует NSJSONSerialization
для создания представления JSON объекта параметров, которое устанавливается в качестве тела запроса. Поле HTTP-заголовка Content-Type
кодированного запроса установлено на application/json
.PropertyList
: использует NSPropertyListSerialization
для создания списка свойств объекта параметров в соответствии со связанными значениями формата и опций записи, который устанавливается в качестве тела запроса. Поле HTTP-заголовка Content-Type
кодированного запроса установлено на application/x-plist
.Custom
: использует связанное значение замыкания для построения нового запроса на основе существующего запроса и параметров.NSURLRequest
let URL = NSURL(string: "http://httpbin.org/get")
var request = NSURLRequest(URL: URL)
let parameters = ["foo": "bar"]
let encoding = Alamofire.ParameterEncoding.URL
(request, _) = encoding.encode(request, parameters)
let parameters = [
"foo": [1,2,3],
"bar": [
"baz": "qux"
]
]
Alamofire.request(.POST, "http://httpbin.org/post", parameters: parameters, encoding: .JSON)
// HTTP body: {"foo": [1, 2, 3], "bar": {"baz": "qux"}}
Кэширование обрабатывается на уровне системной инфраструктуры с помощью NSURLCache
(https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html#//apple_ref/occ/cl/NSURLCache).
Поддерживаемые типы загрузки
let
``` **Загрузка с использованием Alamofire**
fileURL = NSBundle.mainBundle() .URLForResource("Default", withExtension: "png")
Alamofire.upload(.POST, "http://httpbin.org/post", file: fileURL)
#### Загрузка с отслеживанием прогресса
```swift
Alamofire.upload(.POST, "http://httpbin.org/post", file: fileURL)
.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
println(totalBytesWritten)
}
.responseJSON { (request, response, JSON, error) in
println(JSON)
}
Поддерживаемые типы скачивания
Alamofire.download(.GET, "http://httpbin.org/stream/100", destination: { (temporaryURL, response) in
if let directoryURL = NSFileManager.defaultManager()
.URLsForDirectory(.DocumentDirectory,
inDomains: .UserDomainMask)[0]
as? NSURL {
let pathComponent = response.suggestedFilename
return directoryURL.URLByAppendingPathComponent(pathComponent!)
}
return temporaryURL
})
let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
Alamofife.download(.GET, "http://httpbin.org/stream/100", destination: destination)
Alamofire.download(.GET, "http://httpbin.org/stream/100", destination: destination)
.progress { (bytesRead, totalBytesRead, totalBytesExpectedToRead) in
println(totalBytesRead)
}
.response { (request, response, _, error) in
println(response)
}
Аутентификация обрабатывается на уровне системной инфраструктуры с помощью NSURLCredential
и NSURLAuthenticationChallenge
.
Поддерживаемые схемы аутентификации
let user = "user"
let password = "password"
Alamofire.request(.GET, "https://httpbin.org/basic-auth/\(user)/\(password)")
.authenticate(user: user, password: password)
.response {(request, response, _, error) in
println(response)
}
let user = "user"
let password = "password"
let credential = NSURLCrediential(user: user, password: password, persistence: .ForSession)
Alamofire.request(.GET, "https://httpbin.org/basic-auth/\(user)/\(password)")
.authenticate(usingCredential: credential)
.response {(request, response, _, error) in
println(response)
}
По умолчанию Alamofire считает любой завершённый запрос успешным, независимо от содержимого ответа. Вызов validate
перед обработчиком ответа вызывает ошибку, если ответ имеет неприемлемый код состояния или тип MIME.
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.response { (_, _, _, error) in
println(error)
}
Автоматически проверяет код состояния в диапазоне 200...299
, а также соответствие заголовка Content-Type
ответа заголовку Accept
запроса, если он предоставлен.
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
.validate()
.response { (_, _, _, error) in
println(error)
}
``` **let request = Alamofire.request(.GET, "http://httpbin.org/ip")**
println(request)
// GET http://httpbin.org/ip (200)
**let request = Alamofire.request(.GET, «http://httpbin.org/get», parameters: [«foo»: «bar»])**
debugPrintln(request)
#### Output (cURL)
$ curl -i \
-H «User-Agent: Alamofire» \
-H «Accept-Encoding: Accept-Encoding: gzip;q=1.0,compress;q=0.5» \
-H «Accept-Language: en;q=1.0,fr;q=0.9,de;q=0.8,zh-Hans;q=0.7,zh-Hant;q=0.6,ja;q=0.5» \
«http://httpbin.org/get?foo=bar»
---
## Advanced Usage
> Alamofire is built on NSURLSession and the Foundation URL Loading System. To make the most of this framework, it is recommended that you be familiar with the concepts and capabilities of the underlying networking stack.
Recommended Reading
- [URL Loading System Programming Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html)
- [NSURLSession Class Reference](https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/Introduction/Introduction.html#//apple_ref/occ/cl/NSURLSession)
- [NSURLCache Class Reference](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html#//apple_ref/occ/cl/NSURLCache)
- [NSURLAuthenticationChallenge Class Reference](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLAuthenticationChallenge_Class/Reference/Reference.html)
### Manager
Top-level convenience methods like Alamofire.request use a shared instance of Alamofire.Manager, which is configured with the default NSURLSessionConfiguration.
As such, the following two statements are equivalent:
Alamofire.request(.GET, «http://httpbin.org/get»)
let manager = Alamofire.Manager.sharedInstance
manager.request(NSURLRequest(URL: NSURL(string: «http://httpbin.org/get»)))
Applications can create managers for background and ephemeral sessions, as well as new managers that customize the default session configuration, such as for default headers (HTTPAdditionalHeaders) or timeout interval (timeoutIntervalForRequest).
#### Creating a Manager with Default Configuration
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let manager = Alamofire.Manager(configuration: configuration)
#### Creating a Manager with Background Configuration
let configuration = NSURLSessionConfiguration.backgroundSessionConfiguration("com.example.app.background")
let manager = Alamofire.Manager(configuration: configuration)
#### Creating a Manager with Ephemeral Configuration
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
let manager = Alamofire.Manager(configuration: configuration)
#### Modifying Session Configuration
var defaultHeaders = Alamofire.Manager.sharedInstance.session.configuration.HTTPAdditionalHeaders ?? [:]
defaultHeaders["DNT"] = "1 (Do Not Track Enabled)"
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = defaultHeaders
let manager = Alamofire.Manager(configuration: configuration)
> This is not recommended for Authorization or Content-Type headers. Instead, use URLRequestConvertible and ParameterEncoding, respectively.
### Request
The result of a request, upload, or download method is an instance of Alamofire.Request. A request is always created using a constructor method from an owning manager, and never initialized directly.
Methods like authenticate, validate, and response return the caller in order to facilitate chaining.
Requests can be suspended, resumed, and cancelled:
* suspend(): Suspends the underlying task and dispatch queue
* resume(): Resumes the underlying task and dispatch queue. If the owning manager does not have startRequestsImmediately set to true, the request must call resume() in order to start. **Отмена (cancel())**: отменяет основную задачу, создавая ошибку, которая передаётся любым зарегистрированным обработчикам ответа.
### Сериализация ответа
#### Создание пользовательского сериализатора ответа
Alamofire предоставляет встроенную сериализацию ответов для строк, JSON и списков свойств, но можно добавить и другие в расширениях на `Alamofire.Request`.
Например, вот как может быть реализован обработчик ответа с использованием [Ono](https://github.com/mattt/Ono):
```swift
extension Request {
class func XMLResponseSerializer() -> Serializer {
return { (request, response, data) in
if data == nil {
return (nil, nil)
}
var XMLSerializationError: NSError?
let XML = ONOXMLDocument.XMLDocumentWithData(data, &XMLSerializationError)
return (XML, XMLSerializationError)
}
}
func responseXMLDocument(completionHandler: (NSURLRequest, NSHTTPURLResponse?, OnoXMLDocument?, NSError?) -> Void) -> Self {
return response(serializer: Request.XMLResponseSerializer(), completionHandler: { (request, response, XML, error) in
completionHandler(request, response, XML, error)
})
}
}
Дженерики можно использовать для обеспечения автоматической и типобезопасной сериализации объектов ответа.
@objc public protocol ResponseObjectSerializable {
init(response: NSHTTPURLResponse, representation: AnyObject)
}
extension Alamofire.Request {
public func responseObject<T: ResponseObjectSerializable>(completionHandler: (NSURLRequest, NSHTTPURLResponse?, T?, NSError?) -> Void) -> Self {
let serializer: Serializer = { (request, response, data) in
let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let (JSON: AnyObject?, serializationError) = JSONSerializer(request, response, data)
if response != nil && JSON != nil {
return (T(response: response!, representation: JSON!), nil)
} else {
return (nil, serializationError)
}
}
return response(serializer: serializer, completionHandler: { (request, response, object, error) in
completionHandler(request, response, object as? T, error)
})
}
}
class User: ResponseObjectSerializable {
let username: String
let name: String
required init(response: NSHTTPURLResponse, representation: AnyObject) {
self.username = response.URL!.lastPathComponent
self.name = representation.valueForKeyPath("name") as String
}
}
Alamofire.request(.GET, "http://example.com/users/mattt")
.responseObject { (_, _, user: User?, _) in
println(user)
}
Тот же подход можно использовать и для обработки конечных точек, которые возвращают представление коллекции объектов:
@objc public protocol ResponseCollectionSerializable {
class func collection(#response: NSHTTPURLResponse, representation: AnyObject) -> [Self]
}
extension Alamofire.Request {
public func responseCollection<T: ResponseCollectionSerializable>(completionHandler: (NSURLRequest, NSHTTPURLResponse?, [T]?, NSError?) -> Void) -> Self {
let serializer: Serializer = { (request, response, data) in
let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let (JSON: AnyObject?, serializationError) = JSONSerializer(request, response, data)
if response != nil && JSON != nil {
return (T.collection(response: response!, representation: JSON!), nil)
} else {
return (nil, serializationError)
}
}
return response(serializer: serializer, completionHandler: { (request, response, object, error) in
completionHandler(request, response, object as? [T], error)
})
}
}
Типы, соответствующие протоколу URLStringConvertible
, могут использоваться для создания строк URL, которые затем используются для построения запросов URL. Методы удобства верхнего уровня, принимающие аргумент URLStringConvertible
, обеспечивают типобезопасное поведение маршрутизации.
Приложениям, активно взаимодействующим с веб-приложениями, рекомендуется использовать URLStringConvertible
или URLRequestConvertible
для обеспечения согласованности запрашиваемых конечных точек.
enum Router: URLStringConvertible {
static let baseURLString = "http://example.com"
case Root
case User(String)
case Post(Int, Int, String)
// MARK: URLStringConvertible
var URLString: String {
let path: String = {
switch self {
case .Root:
return "/"
case .User(let username):
return "/users/\(username)"
case .Post(let year, let month, let title):
let slug = title.stringByReplacingOccurrencesOfString(" ", withString: "-").lowercaseString
return "/\(year)/\(month)/\(slug)"
}
}()
return Router.baseURLString + path
}
}
Alamofire.request(.GET, Router.User("mattt"))
URLRequestConvertible
**Типы, использующие протокол URLRequestConvertible
, могут быть использованы для создания URL-запросов. Как и URLStringConvertible
, это рекомендуется для приложений со значительным взаимодействием между клиентом и сервером.
Методы верхнего уровня и методы экземпляра в Manager
, принимающие аргументы URLRequestConvertible
, предоставляют способ обеспечения типобезопасной маршрутизации. Такой подход может использоваться для абстрагирования несоответствий на стороне сервера, а также для управления учётными данными аутентификации и другим состоянием.
API-параметры абстракции
enum Router: URLRequestConvertible {
static let baseURLString = "http://example.com"
static let perPage = 50
case Search(query: String, page: Int)
// MARK: URLRequestConvertible
var URLRequest: NSURLRequest {
let (path: String, parameters: [String: AnyObject]?) = {
switch self {
case .Search(let query, let page) where page > 1:
return ("/search", ["q": query, "offset": Router.perPage * page])
case .Search(let query, _):
return ("/search", ["q": query])
}
}()
let URL = NSURL(string: Router.baseURLString)
let URLRequest = NSURLRequest(URL: URL.URLByAppendingPathComponent(path))
let encoding = Alamofire.ParameterEncoding.URL
return encoding.encode(URLRequest, parameters: parameters).0
}
}
Alamofire.request(Router.Search(query: "foo bar", page: 1)) // ?q=foo+bar&offset=50
CRUD и авторизация
enum Router: URLRequestConvertible {
static let baseURLString = "http://example.com"
static var OAuthToken: String?
case CreateUser([String: AnyObject])
case ReadUser(String)
case UpdateUser(String, [String: AnyObject])
case DestroyUser(String)
var method: Alamofire.Method {
switch self {
case .CreateUser:
return .POST
case .ReadUser:
return .GET
case .UpdateUser:
return .PUT
case .DestroyUser:
return .DELETE
}
}
var path: String {
switch self {
case .CreateUser:
return "/users"
case .ReadUser(let username):
return "/users/\(username)"
case .UpdateUser(let username, _):
return "/users/\(username)"
case .DestroyUser(let username):
return "/users/\(username)"
}
}
// MARK: URLRequestConvertible
var URLRequest: NSURLRequest {
let URL = NSURL(string: Router.baseURLString)
let mutableURLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(path))
mutableURLRequest.HTTPMethod = method.toRaw()
if let token = Router.OAuthToken {
mutableURLRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
}
switch self {
case .CreateUser(let parameters):
``` **Перевод текста на русский язык:**
return Alamofire.ParameterEncoding.JSON.encode(mutableURLRequest, parameters: parameters).0 case .UpdateUser(_, let parameters): return Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: parameters).0 default: return mutableURLRequest } } }
* * *
## FAQ
### Когда следует использовать Alamofire?
Если вы начинаете новый проект на Swift и хотите в полной мере воспользоваться его соглашениями и языковыми функциями, Alamofire — отличный выбор. Хотя он не так многофункционален, как AFNetworking, с Alamofire гораздо приятнее работать, и он должен удовлетворить подавляющее большинство случаев использования сетей.
> Важно отметить, что две библиотеки не исключают друг друга: AFNetworking и Alamofire могут мирно сосуществовать в одной кодовой базе.
### Когда следует использовать AFNetworking?
AFNetworking остаётся главной сетевой библиотекой, доступной для OS X и iOS, и может легко использоваться в Swift, как и любой другой код Objective-C. AFNetworking стабилен и надёжен, и никуда не денется.
Используйте AFNetworking в следующих случаях:
- расширения UIKit, такие как асинхронная загрузка изображений в `UIImageView`;
- проверка TLS с помощью `AFSecurityManager`;
- ситуации, требующие `NSOperation` или `NSURLConnection`, с использованием `AFURLConnectionOperation`;
- мониторинг доступности сети с помощью `AFNetworkReachabilityManager`;
- создание многокомпонентных HTTP-запросов с использованием `AFHTTPRequestSerializer`.
### Откуда произошло название Alamofire?
Alamofire назван в честь цветка [Alamo Fire](https://aggie-horticulture.tamu.edu/wildseed/alamofire.html), гибридного варианта Bluebonnet, официального государственного цветка Техаса.
* * *
## Контакты
Следите за AFNetworking в Twitter ([@AFNetworking](https://twitter.com/AFNetworking))
### Создатель
— Мэтт Томпсон (Mattt Thompson) ([@mattt](https://twitter.com/mattt)).
## Лицензия
Alamofire выпущен под лицензией MIT. Подробнее см. в файле LICENSE.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )