앱을 만들다보면 웹서버와 통신이 필요한 경우가 많다.
웹 서버 통신은 크게 2가지로 나눌 수 있는데,
- HTTP 통신: URL 기반으로 클라이언트에게 요청을 보내고, 서버로부터 응답을 받는 형태
- 웹소켓 통신: 클라이언트와 서버가 특정 port를 통해 연결되어 있는 양방향 형태. 실시간 통신에 주로 사용.
→ 이 중에서 HTTP/HTTPS 통신 방법을 URLSession으로 알아볼 것이다.
Class
An object that coordinates a group of related, network data transfer tasks.
- URLSession은 네트워크 데이터를 전송하는 일을 한다.
- URLSession은 URL의 endpoint로부터
데이터를 다운로드/업로드하는 API
를 제공하는 '클래스'다. - 앱이
not running
,suspend
상태에서 background download를 수행할 수 있도록 하기 위해 이 API를 사용할 수도 있다.
URLSessionDelagate와 URLSessionTaskDelegate와 관련된 것을 사용하여 authentication
을 지원하거나 redirection
이나 task completion
같은 이벤트를 받을 수 있다.
- URL session API 는
thread-safe
하다. - session과 task들을 어느 thread context에서든 자유롭게 생성할 수 있다.
→ 자체적으로 비동기적으로 작동하게 구현되어있으므로, 따로 비동기 처리를 할 필요가 없다.
대신 completionHandler
를 작성할 때, UI관련 작업을 수행한다면 반드시 Main thread
에서 작업해주어야 한다.
ex.
하나의 탭 또는 ㅊ아마다 하나의 세션을 만들어 볼 수 있고,
한 세션은 상호작용하는 데 사용, 다른 하나는 백그라운드에서 다운로드하는데 사용할 수 있다.
다운로드가 완료된 후, UI를 업데이트 하고 싶다면 main thread에서 작업한다.
URLSession은 configuration이라는 객체를 가지고 있다.
(업로드를 할 지, 다운로드를 할 지 등의 행동과 규칙을 정의하는 객체.)
- URLSession 객체를 초기화 하기 전에 가장 먼저 작업해야할 첫 단계이며,
타임아웃값, 캐싱 정책, HTTP header와 같은 값들로 구성된다.
.default
.epemeral
.background
configuration의 복사본으로 session을 세팅한다.
따라서 session이 생성되고 난 이후에 configuration 객체가 변동되어도 session은 변하지 않는다.
→ configuration을 수정하고 싶으면, 새로운 configuration으로 새로운 session을 만들어야 함!
URLSession의 종류는 configuration 객체에 의해 결저된다.
let sharedSession = URLSesssion.shared()
- 기본 요청을 위한 세션
- configuration 객체 없음
- 사용자 정의 불가
let defaultSession = URLSession(configuration: .default)
- disk에 기록함( 캐시, 쿠키, authentication)
- delegate 지정 가능 (순차적 데이터 처리)
let ephemeralSession = URLSession(configuration: .ephemeral)
- disk에 데이터를 쓰지 않음
- 메모리에 올려서 세션을 연결
- 세션 만료 시 데이터가 사라진다. → 비공개 세션
let brackgroundSession = URLSession(configuration: .background)
- 백그라운드에서 업로드, 다운로드 가능
- 별도의 프로세스가 모든 데이터 전송을 처리 → suspend, not running 상태에서도 수행
- 참고 링크 - raywenderlich urlsession tutorial
각 세션 내에는 task를 추가할 수 있다.
각 task는 특정 URL에 대한 요청을 의미하며, HTTP redirection이 될 수 있다.
URL 주소만으로 요청할 때는 URL 객체를 이용하고,
주소와 HTTP 메소드, Body 까지 설정해야 할 때는 URLRequest 객체를 이용하면 된다.
// URL 객체
let url = URL(string: "https://api.address.com")
// URRequest 객체
let request: URLRequest = URLReuest(url: url)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Accept")
→ URLRequest는 캐싱 정책, HTTP method, HTTP body 등을 설정할 수 있다.
URLSessionDataTask (HTTP GET)
- reponse data를 받아서 Data 형태의 객체를 받아오는 작업
- JSON, XML, HTML
URLSessionUploadTask (HTTP POST/PUT)
- Data 객체 또는 파일 형태의 데이터를 서버로 업로드 하는 작업 (백그라운드 ok)
URLSessionDownloadTask
- 파일 형태의 데이터를 다운로드 하는 작업 (백그라운드 Ok)
- 일시정지, 재개, 취소 가능
+ 웹소켓 작업은 URLSession이 아니라 WebSocket 프로토콜을 사용
session.dataTasks(with:)
extension URLSession {
func request<T: Decodable>(_ request: URLRequest, completion: @escaping(T?, APIError?) -> Void) {
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async {
guard error == nil else {
completion(nil, .failed)
return
}
guard let data = data else {
completion(nil, .noData)
return
}
guard let response = response as? HTTPURLResponse else {
completion(nil, .invalidResponse)
return
}
guard response.statusCode == 200 else {
completion(nil, .failed)
return
}
do {
let decoder = JSONDecoder()
let userData = try decoder.decode(T.self, from: data)
completion(userData, nil)
} catch {
completion(nil, .invalideData)
}
}
}.resume()
}
}