[iOS] URLSession을 알아야 할까?

모든 iOS 앱은 URLSession을 사용하고 있다고 해도 과언이 아니다. 이번 글에서는 거의 모든 앱에서 사용하는 URLSession에 대해서 알아보자.

 

 

URLSession??

 

 iOS 앱에서 서버와 통신하기 위해 애플에서 제공하는 API이다. URLSession을 활용하면 iOS 앱이 실행 중이지 않을 때도 백그라운드에서 다운로드가 가능하다. 그리고 URLSession을 프로젝트에서 사용할 수 있겠지만 이를 추상화한 Alamofire나 Moya를 보통 많이 사용한다. 즉, Alamofire나 Moya 역시 URLSession을 기반으로 동작을 하는 것이기 때문에, URLSession에 대해 알아둘 필요가 있다.

 

 

 

URLSessionConfiguration

 

 URLSessionConfiguration에서 프로퍼티 설정, 쿠키 정책, 보안 정책, 캐시 정책, 백그라운드 전송 등을 설정할 수 있다.

 

 종류는 4가지가 있다.

  • shared session
  • default session
  • ephemeral(secret mode)
  • background

Shared Session

  • singleton session으로 기본적인 요청을 할 때 사용된다. 
  • 커스텀을 할 수가 없다. 즉, delegate나 configuration 설정 불가 
// shared 세션
URLSession.shared.dataTask(with: request) { data, response, error
...

Default Session

  • 커스텀이 가능하지만 기본적인 기능만 사용 가능하다.
  • Delegate를 이용해 데이터를 점진적으로 받아오는 것이 가능하다.
  • 디스크 기반 캐싱을 지원한다.

디스크 기반 캐싱이란?

- 네트워크 요청의 응답 데이터를 디스크에 저장하여, 이후 동일한 요청이 발생했을 때 네트워크를 통해 다시 요청하는 대신 디스크에 저장된 응답 데이터를 사용하는 방식

- 네트워크 트래픽을 줄이고, 응답 시간을 단축시킬 수 있다.

Ephemeral Session

  • shared 싱글톤 세션과 유사하지만 캐시, 쿠키 또는 인증 정보를 디스크에 남기지 않는 세션이다.
  • private한 기능을 구현할 때 사용한다. (ex. 인터넷 브라우저에 시크릿 모드..)

Background Session

  • 앱이 실행되지 않는 백그라운드에서 콘텐츠 업로드 및 다운로드를 수행할 수 있다.
let session = URLSession(configuration: .default)
let session = URLSession(configuration: .ephemeral)
let session = URLSession(configuration: .background(withIdentifier: "background"))

 

URLSessionTask

 

 작업들을 관리하는 세션 객체들이 생성된 이후에 실제로 데이터를 받거나 보내는 작업을 하는 Task가 생성된다. 이를 통해 네트워크 요청을 수행한다.

 

종류는 5가지가 있다.

  • dataTask
  • uploadTask
  • downloadTask
  • websocketTask
  • streamTask

DataTask

  • 서버와 데이터를 주고받을 때 사용
  • 주로 간단한 데이터를 주고받거나, JSON, XML 같은 구조화된 데이터를 주고받을 때 사용

UploadTask

  • 파일 또는 데이터를 서버로 업로드하는 작업을 처리할 때 사용
  • 예를 들어 파일 업로드, 대용량 데이터 전송 시 사용
  • 백그라운드에서도 업로드 가능

DownloadTask

  • 파일을 서버로부터 다운로드하는 작업을 처리할 때 사용
  • 파일 다운로드, 대용량 파일 수신
  • 백그라운드에서 다운로드 가능

StreamTask

  • TCP/IP 연결을 통해 데이터를 스트리밍하는 작업을 처리
  • 실시간 데이터 전송, 스트리밍 등

WebsocketTask

  • 실시간 양방향 통신할 때 사용
  • 실시간 채팅, 게임 등

 

 

URLRequest

 

 URLRequest는 네트워크 요청에 대한 정보를 포함하는 객체이다. 여기에는 URL, HTTP 메서드, 헤더 등의 정보를 포함하게 된다.

let url = URL(string: 네트워크 통신 url)
var request = URLRequest(url: url!)
request.httpMethod = "GET"
...

 

위와 같이 네트워크 통신을 할 url을 만들고, URLRequest를 생성한다. 이후 메서드나 path, 헤더 등의 정보를 추가해 줄 수 있다.

 

 

 

URLResponse

 

 URLResponse는 네트워크 응답에 대한 정보를 포함하는 객체로, 응답 상태 코드, 헤더 등의 정보를 포함한다.

let task = session.dataTask(with: url) { data, response, error in
        // 에러 처리
        if let error = error {
            print("Error: \(error)")
            return
        }

        // 응답 처리
        if let response = response as? HTTPURLResponse {
            print("Status Code: \(response.statusCode)") // 상태 코드 출력
            print("Headers: \(response.allHeaderFields)") // 헤더 출력
        }

        // 데이터 처리
        if let data = data {
            // 받은 데이터 처리 (예: JSON 파싱)
            print("Data received: \(data)")
        }
    }
    task.resume()

 

이 코드에서 response를 사용해 상태 코드를 비롯한 정보를 받을 수 있으며, data 역시 받을 수 있다.

 

 

URLSessionDelegate

 

  • URLSession.shared가 아닌 Configuration을 설정했을 때 사용 가능하다.
  • 네트워크 요청의 다양한 이벤트를 처리할 수 있다.
  • 백그라운드 작업 관리, 네트워크 작업 재시도 및 오류 처리, 커스텀 캐싱 및 쿠키 관리 
  • delegate를 사용하면 중간 중간 진행 상황을 받을 수 있다. 하지만 만약 위의 URLResponse의 예제 코드처럼 completionHandler를 사용한다면 요청이 100% 완료되었을 때만 결과를 받을 수 있다.

 

 

Thread Safety

 

URLSession은 thread safe하다. 어떤 스레드에서든지 세션이나 테스크를 만들 수 있고, delegate 메서드가 completionHandler를 호출할 때, 그 작업은 자동으로 적절한 delegate 큐로 스케줄링된다. 즉, 여러 스레드가 동시에 접근하더라도 동시에 안전하게 사용할 수 있게 설계되었다는 것이다. 만약 Thread Safety 하지 않다면, 데이터 경합(Race Condition)이 발생할 수 있고, 데이터 손상 혹은 충돌이 일어날 수도 있다.