Alamofire Document를 번역한 글 입니다.

(오타 오역이 많을 수 있습니다)

소개

Alamofire은 HTTP 네트워크 요청에 대한 우아하고 구성 가능한 인터페이스를 제공합니다. 자체 HTTP 네트워킹 기능을 구현하지 않습니다. 대신 Foundation 프레임워크에서 제공하는 Apple의 URL Loading System을 기반으로 구축됩니다.이 시스템의 핵심은 URLSession 및 URLSessionTask 하위 클래스 라는 것 입니다. Alamofire은 이러한 API를 사용하기 쉬운 인터페이스로 래핑하고 HTTP 네트워킹을 사용하는 최신 애플리케이션 개발에 필요한 다양한 기능을 제공합니다. 그러나 Alamofire의 핵심 동작 중 많은 부분이 어디에서 나오는지 아는 것이 중요하므로 URL Loading System에 대해 잘 알고 있는 것이 중요합니다. 궁극적으로 Alamofire의 네트워킹 기능은 URL Loading System의 기능에 따라 제한되며 동작과 모범사례는 항상 기억하고 준수해야합니다.

또한 Alamofire(및 일반적인 URL Loading System)의 네트워킹은 비동기적으로 수행됩니다. 비동기 프로그램은 이 개념에 익숙하지 않은 프로그래머에게는 좌절할 수 있지만 이런방식으로 하는데는 아주 좋은 이유가 있습니다.

 

Aside: The AF Namespace and Reference

Alamofire 설명서의 이전버전에는 Alamofire.request()와 같은 예시를 사용하였습니다. 이 API는 Alamofire 접두사가 필요한것처럼 보이지만 실제로 Alamofire접두사 없이도 잘 작동하였습니다. 요청방법 및 기타기능들은 import Alamofire 가 있는 모든 파일에서 전역적으로 사용 가능했었습니다. Alamofire 5 시작되면서 이 기능은 제거되고 대신에 AF 전역은 Session.defualt에 대한 참조입니다.(AF. 접두사를 사용하여 Alamofire의 기능을 전역으로 사용한다.) 이를 통해 Alamofire은 사용할 때마다 전역 네임스페이스를 오염시키지않고  전역적으로 Session API를 복제할 필요 없이 동일한 편의 기능을 제공할 수 있습니다. 마찬가지로 Alamofire에 의해 확장된 유형은 af 속성 확장을 사용하여 Alamofire가 추가하는 기능을 다른 확장들과 분리 합니다.

 

Making Requests

Alamofire HTTP Request 만드는 다양한 편의 방법을 제공합니다. 가장 간단하게는 URL 변환할  있는 String 제공하기만 하면 됩니다.

AF.request("https://httpbin.org/get").response { response in
    debugPrint(response)
}

- 모든 예제는 import Alamofire 소스 파일 어딘가에 있어야합니다.

 

이것은 실제로 Alamofire's Session type에서 요청을 만드는 두 가지 최상위 API중 한 형태 입니다. 전체 정의는 다음과 같습니다.

open func request<Parameters: Encodable>(_ convertible: URLConvertible,
                                         method: HTTPMethod = .get,
                                         parameters: Parameters? = nil,
                                         encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
                                         headers: HTTPHeaders? = nil,
                                         interceptor: RequestInterceptor? = nil) -> DataRequest

이 방법은 method  headers 같은 개별 구성 요소의 요청을 구성하는 것을 허용하는 동시에 요청별 RequestInterceptor및 Encodable 매개변수를 허용하는 DataRequest을 생성합니다.

- 추가적으로 Parameters dictionaries 와 ParameterEncoding types 을 사용하여 요청을 구성하는 방법이 있습니다. 이 API는 더이상 권장되지 않으며 Alamofire에서 사용되지 않고 제거될 예정입니다.

 

이 API의 두 번째 버전은 훨씬 간단합니다.

open func request(_ urlRequest: URLRequestConvertible, 
                  interceptor: RequestInterceptor? = nil) -> DataRequest

이 방법은 Alamofire의 URLRequestConvertible 프르토콜을 따르는 모든 유형에 대해 DataRequest를 생성합니다. 이전 버전의 모든 다른 매개변수는 해당 값에 캡슐화되어 매우 강력한 추상화를 생성할 수 있습니다. 

 

HTTP Method

이 HTTPMethod 유형은 RFC 7231 에 정의된 HTTP Method 를 나열합니다.

public struct HTTPMethod: RawRepresentable, Equatable, Hashable {
    public static let connect = HTTPMethod(rawValue: "CONNECT")
    public static let delete = HTTPMethod(rawValue: "DELETE")
    public static let get = HTTPMethod(rawValue: "GET")
    public static let head = HTTPMethod(rawValue: "HEAD")
    public static let options = HTTPMethod(rawValue: "OPTIONS")
    public static let patch = HTTPMethod(rawValue: "PATCH")
    public static let post = HTTPMethod(rawValue: "POST")
    public static let put = HTTPMethod(rawValue: "PUT")
    public static let query = HTTPMethod(rawValue: "QUERY")
    public static let trace = HTTPMethod(rawValue: "TRACE")

    public let rawValue: String

    public init(rawValue: String) {
        self.rawValue = rawValue
    }
}

이러한 값들은 AF.request API의 method인자로 전달할 수 있습니다.

AF.request("https://httpbin.org/get")
AF.request("https://httpbin.org/post", method: .post)
AF.request("https://httpbin.org/put", method: .put)
AF.request("https://httpbin.org/delete", method: .delete)

다양한 HTTP Method 는 서버에 따라 다른 의미를 가질 수 있고 다른 매개변수 인코딩이 필요할 수 있다는 점을 기억하는 것이 중요합니다. 예를 들어, GET 요청에서 본문데이터를 전달하는 것은 Alamofire와 URLSession에서 지원되지 않으며 오류를 반환합니다.

Alamofire은 또한 String을 HTTPMethod 값으로 반환하는 httpMethod 속성을 연결하기 위해 URLRequest에 대한 확장 기능을 제공합니다.

extension URLRequest {
    /// Returns the `httpMethod` as Alamofire's `HTTPMethod` type.
    public var method: HTTPMethod? {
        get { httpMethod.flatMap(HTTPMethod.init) }
        set { httpMethod = newValue?.rawValue }
    }
}

 

Alamofire의 HTTPMethod 유형이 지원하지 않는 HTTP Method 를 사용해야 하는 경우 유형을 확장하여 사용자 정의 값을 추가할 수 있습니다.

extension HTTPMethod {
    static let custom = HTTPMethod(rawValue: "CUSTOM")
}

AF.request("https://httpbin.org/headers", method: .custom)

 

 

Setting Other URLRequest Properties

Alamofire의 요청 생성 방법은 사용자 정의를 위한 가장 일반적인 매개변수를 제공하지만 때로는 이것만으로는 충분하지 않을 수 있습니다. 전달된 값에서 생성된 URLRequest 들은 요청을 생성할 때 RequestModifier 의 클로저를 사용하여 수정할 수 있습니다. 예를 들어, URLRequest의 timeoutInterval을 5초로 설정하려면 클로저에서 요청을 수정합니다.

AF.request("https://httpbin.org/get", requestModifier: { $0.timeoutInterval = 5 }).response(...)

RequestModifier는 후행 클로저 구문에도 적용됩니다.

AF.request("https://httpbin.org/get") { urlRequest in
    urlRequest.timeoutInterval = 5
    urlRequest.allowsConstrainedNetworkAccess = false
}
.response(...)

RequestModifier는 오직 URL및 기타 개별 요소들을 사용하여 생성된 요청에만 적용되고, URLRequsetConvertible로 직접 생성된 값에는 적용되지 않습니다. 이러한 값은 모든 매개변수 자체를 설정할 수 있어야 하기 때문에 적용이 되지 않습니다. 또한 생성중에 대부분의 요청을 수정해야 할 필요가 있다면 URLRequestConvertible을 채택하는 것을 추천합니다.

 

 

Request Parameters and Parameter Encoders

Alamofire는 request의 매개변수로 모든 Encodable유형을 전달하는것을 지원합니다. 이러한 매개변수는 ParameterEncoder 프로토콜을 준수하는 유형을 통해 전달되고 URLRequest에 추가된 다음 네트워크를 통해 전송됩니다. Alamofire는 두가지 ParameterEncoder 채택 유형을 포함: JSONParameterEncoder, URLEncodedFormParameterEncoder. 이러한 유형들은 최신 서비스에서 사용하는 가장 일반적인 인코딩을 포함합니다.

struct Login: Encodable {
    let email: String
    let password: String
}

let login = Login(email: "test@test.test", password: "testPassword")

AF.request("https://httpbin.org/post",
           method: .post,
           parameters: login,
           encoder: JSONParameterEncoder.default).response { response in
    debugPrint(response)
}

 

URLEncodedFormParameterEncoder

URLEncodedFormParameterEncoder는 값을 URL 인코딩 문자열로 인코딩하여 기존 URL 쿼리 문자열로 설정,추가 또는 요청의 HTTP 본문으로 설정합니다. 인코딩된 문자열이 설정되는 위치를 제어하려면 인코딩의 destination을 설정합니다. URLEncodedFormParameterEncoder.Destination 열거형은 세가지 경우가 있습니다.

  • .methodDependent: 인코딩된 쿼리 문자열 결과를 .get, .head와 .delete 요청에 대한 기존 쿼리 문자열에 적용하고 다른 HTTP 메서드를 사용하는 요청에 대해서는 이를 HTTP 본문으로 요청하고 설정합니다.
  • .queryString: 요청 URL의 쿼리에 인코딩된 문자열을 설정하거나 추가합니다.
  • .httpBody: 인코딩된 문자열을 URLRequest 의 HTTP Body로 설정합니다.

HTTP body가 포함된 인코딩된 요청의 Content-Type HTTP Header는 application/x-www-form-urlencoded로 설정 됩니다. Content-Type이 아직 설정되지 않은 경우 charset=utf-8입니다.

내부적으로 URLEncodedFormParameterEncoder는 URLEncodedFormEncoder를 사용하여 Encodable유형에서 URL 인코딩된 형식 문자열로 실제 인코딩을 수행합니다. 이 Encoder는 다양한 유형에 대한 인코딩을 사용자 정의하여 사용할 수 있습니다:

  • ArrayEncoding -> Array
  • BoolEncoding -> Bool
  • DataEncoding -> Data
  • DateEncoding -> Date
  • KeyEncoding -> coding keys
  • SpaceEncoding -> spaces

 

 

GET Request With URL-Encoded Parameters

let parameters = ["foo": "bar"]

// All three of these calls are equivalent
AF.request("https://httpbin.org/get", parameters: parameters) // encoding defaults to `URLEncoding.default`
AF.request("https://httpbin.org/get", parameters: parameters, encoder: URLEncodedFormParameterEncoder.default)
AF.request("https://httpbin.org/get", parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .methodDependent))

// https://httpbin.org/get?foo=bar

 

POST Request With URL-Encoded Parameters

let parameters: [String: [String]] = [
    "foo": ["bar"],
    "baz": ["a", "b"],
    "qux": ["x", "y", "z"]
]

// All three of these calls are equivalent
AF.request("https://httpbin.org/post", method: .post, parameters: parameters)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .httpBody))

// HTTP body: "qux[]=x&qux[]=y&qux[]=z&baz[]=a&baz[]=b&foo[]=bar"

 

Configuring the Sorting of Encoded Values

Swift 4.2부터 Swift의 Dictionary유형에서 사용하는 해싱 알고리즘은 런타임에 앱 시작 간에 다른 무작위 내부 순서를 생성합니다. 이로 인해 인코딩된 매개변수가 순서가 변경되어 캐싱 및 기타 동작에 영향을 미칠 수 있습니다. 기본적으로 URLEncodedFormEncoder는 인코딩된 키-값 쌍을 정렬합니다. 이는 모든 Encodable유형에 대해 일정한 출력을 생성하지만 유형에 의해 구현된 실제 인코딩 순서와 일치하지 않을 수 있습니다. AlphabetizeKeyValuePairs를 false로 설정하여 구현 순서로 돌아갈 수 있지만 사전 순서도 무작위로 지정됩니다.

 

사용자 지정 URLEncodedFormparameterEncoder를 생성할 수 있고 전달된 URLEncodedFormEncoder의 초기화과정에서 원하는 alphabetizeKeyValuePairs을 지정할 수 있습니다.

let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(alphabetizeKeyValuePairs: false))

 

Configuring the Encoding of Array Parameters

컬렉션 유형을 인코딩하는 방법에 대해 알려진 사양이 없기 때문에 기본적으로 Alamofire는 배열 값의 키에 []를 추가하고(foo[]=1&foo[]=2), 중첩된 사전 값의 경우 대괄호로 묶인 키를 추가하는 규칙을 따릅니다. (foo[bar]=baz)

URLEncodedFormEncoder.ArrayEncoding 열거형은 Array 매개변수를 인코딩하기 위해 다음과 같은 방법을 제공합니다.

  • .brackets: 모든 값에 대해 빈 대괄호 세트가 키에 추가됩니다. (기본값)
  • .noBrackets: 괄호는 추가되지않고 키는 그대로 인코딩됩니다.

기본적으로 Alamofire는 .Brackets로 인코딩합니다. foo = [1, 2]가 foo[]=1&foo[]=2로 인코딩됩니다.

.noBracktes로 한다면 foo =[1, 2] 가 foo=1&foo=2로 인코딩됩니다.

 

또한 사용자 지정 URLEncodedFormParameterEncoder를 생성하고 전달된 URLEncodedFormEncoder의 생성과정에서 원하는 ArrayEncoding을 지정할 수 있습니다. 

let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(arrayEncoding: .noBrackets))

 

Configuring the Encoding of Bool Parameters

URLEncodedFormEncoder.BoolEncoding 열거형은 Bool매개변수를 인코딩하기 위해 다음과 같은 방법을 제공합니다.

  • .numeric: true를 1, false를 0으로 인코딩합니다. (기본값)
  • .literal: true와 false를 문자열 리터럴로 인코딩합니다.

기본적으로 Alamofire는 .numberic 인코딩을 사용합니다.

 

또한 사용자 지정 URLEncodedFormParameterEncoder를 생성하고 전달된 URLEncodedFormEncoder의 생성과정에서 원하는 BoolEncoding을 지정할 수 있습니다. 

let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(boolEncoding: .numeric))

 

Configuring the Encoding of Data Parameters

DataEncoding은 Data 매개변수를 인코딩하기 위해 다음과 같은 방법들을 제공합니다.

  • .deferredToData: Data의 기본 Encodable 지원을 사용합니다.
  • .base64: Data를 Base 64로 인코딩된 문자열로 인코딩합니다. (기본값)
  • .custom((Data) -> throws -> String): Data를 주어진 클로저를 인코딩합니다.

또한 사용자 지정 URLEncodedFormParameterEncoder를 생성하고 전달된 URLEncodedFormEncoder의 생성과정에서 원하는 DataEncoding을 지정할 수 있습니다. 

let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(dataEncoding: .base64))

 

Configuring the Encoding of Date Parameters

Date를 String으로 인코딩하는 방법은 너무 많기 때문에 DateEncoding에는 Date 매개변수를 인코딩 하기위한 다음 방법들을 제공합니다.

  • .deferredToDate: Date의 기본적인 Encodable기능들을 사용합니다. (기본값)
  • .secondsSince1970: Date를 1970년 1월 1일 UTC 자정 이후의 초로 인코딩합니다.
  • .millisecondsSince1970: Date를 1970년 1월 1일 UTC 자정 이후의 밀리초로 인코딩합니다.
  • .iso8601: ISO8601 및 RFC3339 표준에 따라 인코딩합니다.
  • .formatted(DateFormatter): 주어진 DataFormatter를 사용하여 인코딩합니다
  • .custom((Date) throws -> String) : 주어진 클로저를 사용하여 인코딩합니다.

또한 사용자 지정 URLEncodedFormParameterEncoder를 생성하고 전달된 URLEncodedFormEncoder의 생성과정에서 원하는 DateEncoding을 지정할 수 있습니다. 

let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(dateEncoding: .iso8601))

 

Configuring the Encoding of Coding Keys

매개변수 키 스타일이 다양하기 때문에 KeyEncoding은 lowerCamelCase의 키에서 키 인코딩을 사용자 정의하는 다음 방법을 제공합니다.

  • .useDefaultKeys: 각 유형에서 지정한 키를 사용합니다. (기본값)
  • .convertToSnakeCase: 키를 스네이크 케이스로 변환합니다. oneTwoThree -> one_two_three
  • .convertToKebabCase: 키를 케밥케이스로 변환합니다. oneTwoThree -> one-two-three
  • .capitalized: 첫글자만 대문자로 변환합니다.(UpperCamelCase) oneTwoThree -> OneTwoThree 
  • .uppercased: 모든 글자를 대문자로 변환합니다. oneTwoThree -> ONETWOTHREE
  • .lowercased: 모든 글자를 소문자로 변환합니다: oneTwoThree -> onetwothree
  • .custom((String) -> String): 주어진 클로저를 사용하여 인코딩합니다.

또한 사용자 지정 URLEncodedFormParameterEncoder를 생성하고 전달된 URLEncodedFormEncoder의 생성과정에서 원하는KeyEncoding을 지정할 수 있습니다. 

let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(keyEncoding: .convertToSnakeCase))

 

 

Configuring the Encoding of Object Key Paths

Nest 객체 키 경로는 일반적으로 괄호를 사용하여 인코딩됩니다. Alamofire의 KeyPathEncoding은 해당 동작을 사용자 정의하기위해 룰을 제공합니다.

  • .brackets - 키 경로의 각 하위 키를 괄호로 묶습니다. parent[child][grandchild]
  • .dots - 키 경로의 각 하위 키를 점으로 구분합니다. parent.child.grandchild

또한 사용자 정의 인코딩 클로저로 인스턴스를 생성하여 고유한 인코딩을 생성할 수 있습니다. 예를 들어, KeyPathEncoding {"-\($0)"}은 각 하위 키 경로를 하이픈으로 구분합니다.(ex: parent-child-grandchild)

사용자 지정 URLEncodedFormParameterEncoder를 생성하고 전달된 URLEncodedFormEncoder의 생성과정에서 원하는KeyPathEncoding을 지정할 수 있습니다. 

let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(keyPathEncoding: .brackets))

 

 

Configuring the Encoding of Spaces

이전 형식의 인코더는 공백을 인코딩하는 데 +가 사용되었으며 일부 서버는 최신 퍼센트 인코딩 대신 이 인코딩을 여전히 사용하므로 Alamofire에는 공백을 인코딩하기 위해 다음 방법이 포함되어 있습니다.

  • .percentEscaped: 표준 퍼센트 이스케이프를 적용하여 공백문자를 인코딩합니다. " "이"%20"으로 인코딩됩니다. (기본값)
  • .plusReplaced: 공백 문자를 +로 대체되어 인코딩합니다. " " -? "+"

사용자 지정 URLEncodedFormParameterEncoder를 생성하고 전달된 URLEncodedFormEncoder의 생성과정에서 원하는SpaceEncoding을 지정할 수 있습니다.

let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(spaceEncoding: .plusReplaced))

 

Configuring the Encoding of Optionals

Optional값을 데이터의 일부 값으로 인코딩하는 것에 대한 표준은 없습니다. 그럼에도 불구하고 Alamofire는 옵션 인코딩을 위해 다음과 같은 방법으로 NilEncoding을 제공합니다.

  • .dropKey: 출력에서 nil값을 완전히 삭제하여 인코딩합니다. 이는 다른 Swift 인코더와 일치합니다. (ex: otherValue=2)
  • .dropValue: 출력에서 nil값을 삭제하여 인코딩합니다. (ex: nilvalue=&otherValue=2)
  • .null: nil값을 문자열 null로 인코딩합니다.(ex: nilvalue=null&otherValue=2)

또한 nil 대체 값을 제공하는 인코딩 클로저를 지정하여 사용자 정의 인코딩을 생성 할 수 있습니다.

extension URLEncodedFormEncoder.NilEncoding {
  static let customEncoding = NilEncoding { "customNilValue" }
}

사용자 지정 URLEncodedFormParameterEncoder를 생성하고 전달된 URLEncodedFormEncoder의 생성과정에서 원하는NilEncoding을 지정할 수 있습니다.

let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(nilEncoding: .dropKey))

 

 

JSONParameterEncoder

JSONParameterEncoder은 Swift의 JSONEncoder를 사용하여 Encodable 값을 인코딩하고 결과를 URLRequest의 httpBody로 설정합니다. 인코딩된 요청의 Content-Type HTTP 헤더 필드는 아직 설정되지 않은 경우 application/json으로 설정됩니다.

 

POST Request with JSON-Encoded Parameters

let parameters: [String: [String]] = [
    "foo": ["bar"],
    "baz": ["a", "b"],
    "qux": ["x", "y", "z"]
]

AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.default)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.prettyPrinted)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.sortedKeys)

// HTTP body: {"baz":["a","b"],"foo":["bar"],"qux":["x","y","z"]}

 

Configuring a Custom JSONEncoder

사용자의 필요에 맞게 구성된 JSONEncoder 인스턴스를 전달하여 JSONParameterEncoder의 동작을 사용자 정의할 수 있습니다.

let encoder = JSONEncoder()
encoder.dateEncoding = .iso8601
encoder.keyEncodingStrategy = .convertToSnakeCase
let parameterEncoder = JSONParameterEncoder(encoder: encoder)

 

Manual Parameter Encoding of a URLRequest

ParameterEncoder API는 URLRequest에서 매개변수를 직접 인코딩하여 Alamofire 외부에서도 사용할 수 있습니다.

let url = URL(string: "https://httpbin.org/get")!
var urlRequest = URLRequest(url: url)

let parameters = ["foo": "bar"]
let encodedURLRequest = try URLEncodedFormParameterEncoder.default.encode(parameters, 
                                                                          into: urlRequest)

 

 

 

HTTP Headers

Alamofire에는 자체 HTTPHeaders 유형이 포함되어 있으며, HTTP 헤더 이름/값 쌍의 순서를 유지하고 대소문자를 구분하지 않는 표현입니다. HTTPHeader 유형은 단일 이름/값 쌍을 캡슐화하고 일반적인 헤더에 대한 다양한 정적 값을 제공합니다.

Request에 사용자 정의 HTTPHeaders 를 추가하는 것은 Request 메서드중 하나에 값을 전달하는 것 만큼 간단합니다.

let headers: HTTPHeaders = [
    "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=",
    "Accept": "application/json"
]

AF.request("https://httpbin.org/headers", headers: headers).responseDecodable(of: DecodableType.self) { response in
    debugPrint(response)
}

HTTPHeaders는 HTTPHeader값의 배열에서도 구성될 수 있습니다.

let headers: HTTPHeaders = [
    .authorization(username: "Username", password: "Password"),
    .accept("application/json")
]

AF.request("https://httpbin.org/headers", headers: headers).responseDecodable(of: DecodableType.self) { response in
    debugPrint(response)
}

- 변경되지 않는 HTTP Headers에 경우에 URLSessionConfiguration에서 설정하여 기본 URLSession에 의해 생성된 모든 URLSessionTask에 자동으로 적용 되도록 설정하는 것이 좋습니다.

 

기본 Alamofire Session은 모든 Request에 대한 기본 Header 세트를 제공합니다. 여기에는 다음이 포함됩니다.

  • Accept-Encoding,  RFC 7230 §4.2.3.에 따라 기본값은 br;q=1.0, gzip;q=0.8, deflate;q=0.6
  • Accept-Language,  RFC 7231 §5.3.5.에 따라 en;q=1.0과 같은 형식으로 시스템에서 기본적으로 사용되는 최대 6개의 언어로 기본설정됩니다.
  • User-Agent, 현재 앱에 대한 버전 관리 정보가 포함되었습니다.(예: iOS Example/1.0 (cohttp://m.alamofire.iOS-Example; build:1; iOS 13.0.0) Alamofire/5.0.0, per RFC 7231 §5.5.3.)

이 헤더를 사용자 지정 하는 경우엔 사용자 지정 URLSessionConfiguration을 생성하고 headers 속성을 업데이트하고 해당 구성을 새로운 Session 인스턴스에 적용해야 합니다. Alamofire의 기본 헤더를 유지하면서 구성을 사용자 정의하려면 URLSesisonConfiguration.af.defualt를 사용하세요.

 

Response Validation

기본적으로 Alamofire는 응답의 내용과 관계없이 완료된 모든 요청을 성공으로 처리합니다. 응답 핸들러이전에 validate()를 호출하면 응답에 허용할 수 없는 상태 코드나 MIME 유형이 있는 경우 오류가 생성됩니다.

 

Automatic Validation

validate() API는 자동으로 상태코드가 200..<300 범위에 있는지 검증하며, requset header가 제공된 경우 응답의 Content-Type 헤더가 request의 Accept 헤더와 일치하는지 검증합니다.

AF.request("https://httpbin.org/get").validate().responseData { response in
    debugPrint(response)
}

 

Manual Validation

AF.request("https://httpbin.org/get")
    .validate(statusCode: 200..<300)
    .validate(contentType: ["application/json"])
    .responseData { response in
        switch response.result {
        case .success:
            print("Validation Successful")
        case let .failure(error):
            print(error)
        }
    }

 

 

 

Response Handling

Alamofire의 DataRequest와 DownloadRequest 둘다 다음 응답 유형을 갖습니다

-> DataResponse<Success, Failure: Error>, DownloadResponse<Success, Failure: Error>

이 둘은 모두 직렬화된 유형과 오류 유형 두가지 제네릭으로 구성됩니다. 기본적으로 모든 응답 값들은 AFError 에러유형을 생성합니다.(DataResponse<Success, AFError>) Alamofire는 공개 API에서 항상 AFError 오류 유형이 있는 더 간단한 AFDateResponse<Success> 및 AFDownloadResponse<Success를 사용합니다. DataRequest의 서브클래스인 UploadRequest도 같은 DataResponse 유형으로 사용합니다.

 

Alamofire에서 생성된 DataRequest 또는 UploadRequest의 DataResponse를 처리하는것은  responseDecodable과 같은 응답 핸들러를 DataRequest에 연결하는것을 포함합니다.

AF.request("https://httpbin.org/get").responseDecodable(of: DecodableType.self) { response in
    debugPrint(response)
}

 

위의 예에서 responseDecodable 핸들러는 DataRequest가 완료되면 실행되도록 DataRequest에 추가됩니다.

핸들러에 전달된 클로저는 URLRequest, HTTPURLResponse, Data 및 Error로부터 DecodableResopnseSerializer가 생성된 DataResponse<DecodableType, AFError>값을 수신합니다.

서버로부터 응답을 기다리기 위해 실행을 차단하는 대신, 이 클로저는 응답을 받으면 응답을 처리하기 위한 콜백으로 추가됩니다. 요청의 결과는 오직 응답 클로저 범위내에서만 사용이 가능합니다. 서버로 부터 받은 데이터나 응답에 따른 모든 실행은 응답 클로저 안에서 실행되어야합니다.

Alamofire 네트워킹은 비동기적으로 실행됩니다. 비동기적 프로그래밍은 개념에 익숙하지 않은 프로그래머에게 좌절감을 줄 수 있지만 이런 방식으로 수행하는 데는 아주 좋은 이유가 있습니다.

Alamofire는 기본적으로 5개의 다양한 데이터 응답 핸들러가 포함되어 있습니다.

// Response Handler - Unserialized Response
func response(queue: DispatchQueue = .main, 
              completionHandler: @escaping (AFDataResponse<Data?>) -> Void) -> Self

// Response Serializer Handler - Serialize using the passed Serializer
func response<Serializer: DataResponseSerializerProtocol>(queue: DispatchQueue = .main,
                                                          responseSerializer: Serializer,
                                                          completionHandler: @escaping (AFDataResponse<Serializer.SerializedObject>) -> Void) -> Self

// Response Data Handler - Serialized into Data
func responseData(queue: DispatchQueue = .main,
                  dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
                  emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
                  emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods,
                  completionHandler: @escaping (AFDataResponse<Data>) -> Void) -> Self

// Response String Handler - Serialized into String
func responseString(queue: DispatchQueue = .main,
                    dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
                    encoding: String.Encoding? = nil,
                    emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
                    emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods,
                    completionHandler: @escaping (AFDataResponse<String>) -> Void) -> Self

// Response Decodable Handler - Serialized into Decodable Type
func responseDecodable<T: Decodable>(of type: T.Type = T.self,
                                     queue: DispatchQueue = .main,
                                     dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
                                     decoder: DataDecoder = JSONDecoder(),
                                     emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
                                     emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods,
                                     completionHandler: @escaping (AFDataResponse<T>) -> Void) -> Self

어떤 응답 처리기도 서버로부터 받은 HTTPURLResponse에 대해 어떠한 검증도 수행하지 않습니다.

- 예를 들어, 400..<500 및 500..<600 범위의 응답 상태 코드는 자동으로 Error를 트리거하지 않습니다. Alamofire는 이를 달성하기 위해 Response Validation method chaining 사용합니다.

 

Response Handler

response 핸들러는 응답 데이터를 평가하지 않습니다. 단지 URLSessionDelegate에서 직접 모든 정보를 전달합니다. 이는 cURL 을 사용하여 Request를 실행하는 것과 동일한 Alamofire입니다.

AF.request("https://httpbin.org/get").response { response in
    debugPrint("Response: \(response)")
}

- Response 및 Result types를 활용할 수 있는 다른 응답 직렬 변환기를 활용하는 것이 좋습니다.

 

Response Data Handler

responseData 핸들러는 DataResponseSerializer를 사용하여 서버에서 반환된 Data를 추출하고 검증합니다. 오류가 발생하지 않고 Data가 추출됬다면 response Result는 .success로 되고 value는 서버에서 반환된 Data가 될것입니다.

AF.request("https://httpbin.org/get").responseData { response in
    debugPrint("Response: \(response)")
}

 

Response String Handler

responseString handler는 StringResponseSerializer를 사용하여 서버로 부터 받은 Data를 지정된 인코딩을 사용하여 String으로 변환합니다. 오류가 발생하지 않고 서버 데이터가 성공적으로 String으로 변환되면 응답 결과는 .success가 되고 값은 String 유형이 됩니다.

AF.request("https://httpbin.org/get").responseString { response in
    debugPrint("Response: \(response)")
}

지정된 인코딩이 없다면 Alamofire는 서버의 HTTPURLResponse에 지정된 텍스트 인코딩을 사용합니다. 만약 서버에서 지정한 텍스트 인코딩이 없다면 기본값인 .isoLatin1으로 사용됩니다.

 

Response Decodable Handler

responseDecodable handler는 DecodableResponseSerializer을 사용하여 지정된 DataDecoder(데이터에서 디코딩할 수 있는 디코더에 대한 프로토콜 추상화)를 사용하여 서버로부터 받은 Data를 Decodable 유형으로 변환합니다. 에러가 발생하지 않고 서버로부터 받은 데이터가 성공적으로 Decodable 유형으로 디코딩 됬다면 응답결과는 .success가 되고, 값은 전달받은 유형이 됩니다.

struct DecodableType: Decodable { let url: String }

AF.request("https://httpbin.org/get").responseDecodable(of: DecodableType.self) { response in
    debugPrint("Response: \(response)")
}

 

Chained Response Handlers

Response handler는 또한 연결될 수 있습니다.

Alamofire.request("https://httpbin.org/get")
    .responseString { response in
        print("Response String: \(response.value)")
    }
    .responseDecodable(of: DecodableType.self) { response in
        print("Response DecodableType: \(response.value)")
    }

- 동일한 요청에 여러 응답 핸들러를 사용하려면 서버 데이터를 각 응답 핸들러에 대해 한번씩 여러번 직렬화해야 한다는 점에 유의하는 것이 중요합니다. 동일한 요청에 여러 응답 핸들러를 사용하는 것은 일반적으로 특히 프로덕션 환경에서 모범 사례로 피해야 합니다. 디버깅이나 더 나은 옵션이 없는 상황에서만 사용해야 합니다.

 

Response Handler Queue

응답핸들러에 전달된 클로저는 기본적으로 .main 큐에서 실행되지만 클로저를 실행하기 위해 특정 DispatchQueue로 전달될 수 있습니다. 실제 직렬화 작업(데이터를 다른 유형으로 변환)은 항상 요청을 발행하는 세션의 rootQueue 또는 serializationQueue(제공된 경우)의 백그라운드에서 실행됩니다.

let utilityQueue = DispatchQueue.global(qos: .utility)

AF.request("https://httpbin.org/get").responseDecodable(of: DecodableType.self, queue: utilityQueue) { response in
    print("This closure is executed on utilityQueue.")
    debugPrint(response)
}

 

 

Response Caching

Response caching은 URLCache에 의해 시스템 프레임워크 수준에서 처리됩니다. 복합적인 in-memory 및 on-disk 캐시를 제공하며 in-memory, on-dist 둘다 크기를 조작할 수 있습니다.

- 기본적으로 Alamofire는 URLCache.shared 인스턴스를 활용합니다. 사용된 URLCache 인스턴스를 사용자 정의하려면 Session Configuration을 참조하세요.

 

Authentication

Authentication은 URLCredential와 URLAuthenticationChallenge에 의해 시스템 프레임워크 수준에서 처리됩니다.

- 이러한 Authentication API는 인증 또는 동등한 헤더가 필요한 API와 함께 일반적으로 사용되지 않고 승인을 요청하는 서버용 입니다.

 

지원되는 인증체계

- HTTP Basic

- HTTP Digest

- Kerberos

- NTLM

 

HTTP Basic Authentication

요청의 인증방법은 URLAuthenticationChallenge로 인증 요청을 받을 때 자동으로 URLCredential을 제공합니다.

let user = "user"
let password = "password"

AF.request("https://httpbin.org/basic-auth/\(user)/\(password)")
    .authenticate(username: user, password: password)
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

 

Authentication with URLCredential

let user = "user"
let password = "password"

let credential = URLCredential(user: user, password: password, persistence: .forSession)

AF.request("https://httpbin.org/basic-auth/\(user)/\(password)")
    .authenticate(with: credential)
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

 

- 인증을 위해 URLCredential사용할 때 서버에서 문제가 발생하면 기본 URLSession은 실제로 두개의 요청을 생성하게 된다는 점에 유의해야합니다. 첫번째 요청에는 서버에서 챌린지를 "촉발할 수 있는" 자격 증명이 포함되지 않습니다. 그런 다음 Alamofire가 챌린지를 수신하고 자격 증명이 추가되며 기본 URLSession이 요청을 다시 시도합니다.

 

Manual Authentication

메세지를 표시하지 않고 항상 인증 또는 유사한 헤더가 필요한 API와 통신하는 경우 수동으로 추가할 수 있습니다.

let user = "user"
let password = "password"

let headers: HTTPHeaders = [.authorization(username: user, password: password)]

AF.request("https://httpbin.org/basic-auth/user/password", headers: headers)
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

그러나 모든 요청에 반드시 포함되어야 하는 헤더는 RequestAdapter를 사용하거나 사용자 지정 URLSessionConfiguration의 부분으로 처리되는게 더 나은 경우가 많습니다.

 

Downloading Data to a File

Alamofire는 메모리로 데이터를 가져오는 것 외에도 디스크로 다운로드 할 수 있게 Session.download, DownloadRequest 그리고 DownloadResponse<Success, Failure: Error> API를 제공합니다. 메모리로 다운로드하는 것은 대부분의 JSON API응답과 같은 작은 페이로드에 적합하지만, 이미지 및 비디오와 같은 더 큰 데이터를 가져오는 것은 애플리케이션의 메모리 문제를 피하기 위해 디스크로 다운로드해야 합니다.

AF.download("https://httpbin.org/image/png").responseURL { response in
    // Read file from provided file URL.
}

DataRequest와 동일한 응답 핸들러를 갖는 것 외에도 DownloadRequest에는 responseURL도 포함됩니다. 다른 응답 핸들러와는 다르게 이 핸들러는 단지 다운로드된 데이터의 위치가 포함된 URL만 반환하고 디스크에서 Data를 읽진 않습니다.

responseDecodable과 같은 다른 핸들러는 디스크에서 응답 Data를 읽는것 까지 포함됩니다. 이것은 아마도 많은양의 데이터를 메모리로 읽어들이는 것이 포함될 수 있으므로 다운로드에 이러한 핸들러를 사용할 때 이를 염두해 두는 것이 중요합니다.

 

Download File Destination

모든 다운로드된 데이터는 처음에는 시스템 임시 디렉토리에 저장됩니다. 언젠가는 시스템에 의해 결국 삭제될 것이므로 더 오래 보관해야 하는 파일이라면 다른곳으로 옮기는 것이 중요합니다.

파일을 임시 디렉토리에서 최종 대상으로 이동하기 위해 대상 클로저를 사용할 수 있습니다. 임시 파일이 실제로 목적지URL로 이동되기 전에 클로저에 지정된 옵션이 실행됩니다. 현재 지원되는 두가지 옵션은 다음과 같습니다.

  • .createIntermediateDirectories: 지정된 경우 대상 URL에 대한 중간 디렉토리를 생성합니다.
  • .removePreviousFile: 지정된 경우 대상 URL에서 이전 파일을 제거합니다.
let destination: DownloadRequest.Destination = { _, _ in
    let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let fileURL = documentsURL.appendingPathComponent("image.png")

    return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}

AF.download("https://httpbin.org/image/png", to: destination).response { response in
    debugPrint(response)

    if response.error == nil, let imagePath = response.fileURL?.path {
        let image = UIImage(contentsOfFile: imagePath)
    }
}

제안된 다운로드 대상 API를 사용할 수도 있습니다.

let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)

AF.download("https://httpbin.org/image/png", to: destination)

 

Download Progress

다운로드 진행 상황을 사용자에게 보고하는 것이 도움이 될 수 있는 경우가 많습니다. 모든 DownloadRequest는 downloadProgress API를 사용하여 다운로드 진행 상황을 보고할 수 있습니다.

AF.download("https://httpbin.org/image/png")
    .downloadProgress { progress in
        print("Download Progress: \(progress.fractionCompleted)")
    }
    .responseData { response in
        if let data = response.value {
            let image = UIImage(data: data)
        }
    }

- URLSession 및 Alamofire의 진행 상황 보고 API는 서버가 진행 상황을 계산하는 데 사용할 수 있는 Content-Length 헤더를 올바르게 반환하는 경우에만 작동합니다. 해당 헤더가 없으면 다운로드가 완료될 때 까지 진행률이 0.0으로 유지되며, 다운로드가 완료되면 진행률이 1.0으로 점프됩니다.

downloadProgress API는 다운로드 진행 클로저가 호출되어야 하는 DispatchQueue를 정의하는 대기열 매개변수를 취할 수도 있습니다.

let progressQueue = DispatchQueue(label: "com.alamofire.progressQueue", qos: .utility)

AF.download("https://httpbin.org/image/png")
    .downloadProgress(queue: progressQueue) { progress in
        print("Download Progress: \(progress.fractionCompleted)")
    }
    .responseData { response in
        if let data = response.value {
            let image = UIImage(data: data)
        }
    }

 

Canceling and Resuming a Download

모든 Request 클래스에 있는 cancel() API외에도 DownloadRequests는 나중에 다운로드를 재개하는 데 사용할 수 있는 ResumeData를 생성할 수 있습니다. 이 API는 두가지 형식이 있습니다. cancel(producingResumeData: Bool)은 ResumeData 생성 여부를 제어할 수 있지만 DownloadResponse에서만 사용할 수 있도록 합니다.

그리고 cancel(byProducingResumeData:(_ resumeData: Data?) -> Void)는 동일한 작업을 수행하지만 완료 핸들러에서 ResumeData를 사용할 수 있게 만듭니다.

DownloadRequest가 취소되거나 중단되면 기본 URLSessionDownloadTask가 ResumeData를 생성할 수 있습니다. 이런 일이 발생하면 ResumeData를 다시 사용하여 중단된 DownloadRequest를 다시 시작할 수 있습니다.

- 중요: 모든 Apple 플랫폼(iOS 10 - 10.2, macOS 10.12 - 10.12.2, tvOS 10 - 10.1, watchOS 3 - 3.1.1)의 일부 버전에서는 ResumeData가 백그라운드 URLSessionConfigurations에서 손상됩니다. ResumeData 생성 로직에는 데이터가 잘못 기록되어 항상 다운로드를 재개하지 못하는 기본 버그가 있습니다. 버그해결은 다음을 참조하세요 https://stackoverflow.com/questions/39346231/resume-nsurlsession-on-ios10/39347461#39347461

 

Resume NSUrlSession on iOS10

iOS 10 is going to be released soon so it worth to test applications for compatibility with it. During such test we've discovered that our app can't resume background downloads on iOS10. Code that ...

stackoverflow.com

var resumeData: Data!

let download = AF.download("https://httpbin.org/image/png").responseData { response in
    if let data = response.value {
        let image = UIImage(data: data)
    }
}

// download.cancel(producingResumeData: true) // Makes resumeData available in response only.
download.cancel { data in
    resumeData = data
}

AF.download(resumingWith: resumeData).responseData { response in
    if let data = response.value {
        let image = UIImage(data: data)
    }
}

 

Updating Data to a Server

JSON 또는 URL 인코딩 매개변수를 사용하여 상대적으로 적은 양의 데이터를 서버에 보낼 때는 일반적으로 request() API로 충분합니다. 메모리 내 데이터, 파일 URL 또는 InputStream에서 훨씬 더 많은 양의 데이터를 보내야하는 경우 upload() API를 사용하는 것이 좋습니다.

 

Uploading Data

let data = Data("data".utf8)

AF.upload(data, to: "https://httpbin.org/post").responseDecodable(of: DecodableType.self) { response in
    debugPrint(response)
}

 

Uploading a File

let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")

AF.upload(fileURL, to: "https://httpbin.org/post").responseDecodable(of: DecodableType.self) { response in
    debugPrint(response)
}

 

Uploading Multipart Form Data

AF.upload(multipartFormData: { multipartFormData in
    multipartFormData.append(Data("one".utf8), withName: "one")
    multipartFormData.append(Data("two".utf8), withName: "two")
}, to: "https://httpbin.org/post")
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

 

Uploading Progress

사용자가 업로드가 완료되기를 기다리는 동안 사용자에게 업로드 진행 상황을 표시하는 것이 편리한 경우가 있습니다. 모든 UploadRequest는 uploadProgress 및 downloadProgress API를 사용하여 업로드의 업로드 진행률과 응답 데이터 다운로드의 다운로드 진행률을 모두 보고할 수 있습니다.

let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")

AF.upload(fileURL, to: "https://httpbin.org/post")
    .uploadProgress { progress in
        print("Upload Progress: \(progress.fractionCompleted)")
    }
    .downloadProgress { progress in
        print("Download Progress: \(progress.fractionCompleted)")
    }
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

 

 

Streaming Data from a Server

시간이 오래걸리는 대규모 다운로드 또는 오래동안 서버 연결은 데이터가 도착했을 때 저장하는 것보다 스트리밍을 통해 제공되는게 더 좋을 방법일 수 있습니다. Alamofire는 이러한 사용을 처리하기 위해 DataStreamRequest유형과 관련 API를 제공합니다. 다른 요청과 동일한 API를 많이 제공하지만 몇 가지 주요 차이점이 있습니다. 특히 DataStreamRequest는 데이터를 메모리에 축적하거나 디스크에 저장하지 않습니다. 대신 데이터가 도착할 때 추가된 responseStream 클로저가 반복적으로 호출됩니다. 연결이 완료되거나 오류가 수신되면 동일한 클로저가 다시 호출됩니다.

모든 핸들러 클로저는 처리중인 이벤트와 요청을 취소하는 데 사용할 수 있는 CancellationToken을 모두 포함하는 스트림 값을 캡처합니다.

public struct Stream<Success, Failure: Error> {
    /// Latest `Event` from the stream.
    public let event: Event<Success, Failure>
    /// Token used to cancel the stream.
    public let token: CancellationToken
    /// Cancel the ongoing stream by canceling the underlying `DataStreamRequest`.
    public func cancel() {
        token.cancel()
    }
}

Event는 두가지 가능한 스트림 상태를 나타내는 열거형입니다.

public enum Event<Success, Failure: Error> {
    /// Output produced every time the instance receives additional `Data`. The associated value contains the
    /// `Result` of processing the incoming `Data`.
    case stream(Result<Success, Failure>)
    /// Output produced when the instance has completed, whether due to stream end, cancellation, or an error.
    /// Associated `Completion` value contains the final state.
    case complete(Completion)
}

완료되면 Completion값에는 스트림이 종료되었을 때 DataStreamRequest의 상태가 포함됩니다.

public struct Completion {
    /// Last `URLRequest` issued by the instance.
    public let request: URLRequest?
    /// Last `HTTPURLResponse` received by the instance.
    public let response: HTTPURLResponse?
    /// Last `URLSessionTaskMetrics` produced for the instance.
    public let metrics: URLSessionTaskMetrics?
    /// `AFError` produced for the instance, if any.
    public let error: AFError?
}

 

Streaming Data

서버에서 데이터 스트리밍은 다른 Alamofire 요청처럼 수행될 수 있지만 핸들러 클로저가 추가됩니다.

func responseStream(on queue: DispatchQueue = .main, stream: @escaping Handler<Data, Never>) -> Self

제공된 queue는 Handler 클로저가 호출되는 위치입니다.

AF.streamRequest(...).responseStream { stream in
    switch stream.event {
    case let .stream(result):
        switch result {
        case let .success(data):
            print(data)
        }
    case let .complete(completion):
        print(completion)
    }
}

- 데이터 수신은 절대 실패할 수 없으므로 위 예제처럼 결과의 .failure 사례를 처리하는 것은 불필요합니다.

 

Streaming 'String's

데이터 스트리밍과 마찬가지로 문자열도 핸들러를 추가하여 스트리밍할 수 있습니다.

func responseStreamString(on queue: DispatchQueue = .main,
                          stream: @escaping StreamHandler<String, Never>) -> Self

문자열 값은 UTF8로 디코딩되며 디코딩이 실패할 수 없습니다.

AF.streamRequest(...).responseStreamString { stream in
    switch stream.event {
    case let .stream(result):
        switch result {
        case let .success(string):
            print(string)
        }
    case let .complete(completion):
        print(completion)
    }
}

 

Streaming Decodable Values

들어오는 스트림 데이터값은 responseStreamDecodable을 사용하여 Decodable 값으로 변환될 수 있습니다.

func responseStreamDecodable<T: Decodable>(of type: T.Type = T.self,
                                           on queue: DispatchQueue = .main,
                                           using decoder: DataDecoder = JSONDecoder(),
                                           preprocessor: DataPreprocessor = PassthroughPreprocessor(),
                                           stream: @escaping Handler<T, AFError>) -> Self

디코딩 실패로 인해 스트림이 종료되지는 않지만 대신 출력 결과에 AFError가 생성됩니다.

AF.streamRequest(...).responseStreamDecodable(of: SomeType.self) { stream in
    switch stream.event {
    case let .stream(result):
        switch result {
        case let .success(value):
            print(value)
        case let .failure(error):
            print(error)
        }
    case let .complete(completion):
        print(completion)
    }
}

 

Producing an InputStream

StreamHandler 클로저를 사용하여 들어오는 데이터를 처리하는 것 외에도 DataStreamRequest는 바이트가 도착할 때 읽는 데 사용할 수 있는 InputStream값을 생성할 수 있습니다.

func asInputStream(bufferSize: Int = 1024) -> InputStream

이러한 방식으로 생성된 InputStream은 읽기가 시작되기 전에 open()을 호출해야 하며, 그렇지 않으면 스트림을 자동으로 여는 API에 전달되어야 합니다. 이 메서드에서 반환된 후에는 InputStream 값을 활성 상태로 유지하고 읽기가 완료된 후 close()를 호출하는 것은 호출자의 책임입니다.

let inputStream = AF.streamRequest(...)
    .responseStream { output in
        ...
    }
    .asInputStream()

 

Cancellation

DataStreamRequest는 네 가지 방법으로 취소할 수 있습니다.

첫째, 다른 모든 Alamofire 요청과 마찬가지로 DataStreamRequest는 cancel()을 호출하여 기본 작업을 취소하고 스트림을 완료할 수 있습니다.

let request = AF.streamRequest(...).responseStream(...)
...
request.cancel()

 

둘째, DataStreamSerializer에 오류가 발생하면 DataStreamRequest가 자동으로 취소될 수 있습니다. 이 동작은 기본적으로 비활성화되어 있으며 요청을 생성할 때 automaticCancelOnStreamError 매개변수를 전달하여 활성화할 수 있습니다.

AF.streamRequest(..., automaticallyCancelOnStreamError: true).responseStream(...)

 

셋째, Handler 클로저에서 오류가 발생하면 DataStreamRequests가 취소됩니다. 이 오류는 요청에 저장되며 완료값에서 사용할 수 있습니다.

AF.streamRequest(...).responseStream { stream in
    // Process stream.
    throw SomeError() // Cancels request.
}

 

마지막으로 Stream값의 cancel() 메서드를 사용하여 DataStreamRequests를 취소할 수 있습니다.

AF.streamRequest(...).responseStream { stream in 
    // Decide to cancel request.
    stream.cancel()
}

 

 

Statistical Metrics

URLSessionTaskMetrics

Alamofire는 모든 요청에 대해 URLSessionTaskMetrics를 수집합니다. URLSessionTaskMetrics는 기본 네트워크 연결과 요청 및 응답 타이밍에 대한 환상적인 통계정보를 캡슐화합니다.

AF.request("https://httpbin.org/get").responseDecodable(of: DecodableType.self) { response in
    print(response.metrics)
}

- FB7624529로 인해 watchOS의 URLSessionTaskMetrics 수집이 현재 비활성화되어 있습니다.

 

cURL Command Output

플랫폼 문제를 디버깅하는 것은 실망스러울 수 있습니다. 다행히 Alamofire의 요청 유형은 쉬운 디버깅을 위해 동등한 cURL 명령을 생성할 수 있습니다. Alamofire 요청 생성의 비동기 특성으로 인해 이 API에는 동기 버전과 비동기 버전이 모두 있습니다. cURL 명령을 최대한 빨리 얻으려면 cURLDescription을 요청에 연결하면 됩니다.

AF.request("https://httpbin.org/get")
    .cURLDescription { description in
        print(description)
    }
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response.metrics)
    }

 

 

 

 

 

 

 

 

 

+ Recent posts