URLSession
URL로 표시된 엔드포인트에서 데이터를 업로드하거나 다운로드하는 등의 API를 제공해 주는 클래스를 말하며, 내부의 여러 설정을 통해 데이터를 어떻게 전송하고 어떻게 동작할지를 설정할 수 있다.
URLSession의 shared의 경우에는 은 싱글톤 객체로 구성되어 있어 사용자가 커스터마이징한 것을 등록할 수는 없지만, 그 사용 범위가 제한적인 경우 내부의 method나 설정을 이용하여 네트워크 통신을 할 수 있다. 간단하고 기본적인 요청일 경우에는 앞서 말한 Shared Session나 조금 더 커스터마이징을 해서 사용할 수 있는 Default Session을 이용하여 사용할 수 있고, 이외에도 다른 Session Configuration을 이용하여 별도의 처리를 할 수 있다.
- URLSessionConfiguration
- 이... 이게 몰까?
- 환경 설정이라고 보면 된다! 일반적인 프로퍼티 설정, 쿠키 정책, 보안 정책, 캐시 정책, 백그라운드 전송 등을 세부적으로 설정할 수 있다.
- 그 예를 들어보자면...
- 앱을 켰을 때 wifi 데이터를 사용할지, 아니면 셀룰러 데이터까지 사용할지를 설정한다든가?
- 브라우저를 열었을 때, 시크릿 브라우저를 띄울지 아니면 일반 브라우저를 띄울지! 라든가
- 보안 / 캐싱 / 세션 처리를 어떻게 할 것인가? 같은 것을 말한다.
- 환경 설정이라고 보면 된다! 일반적인 프로퍼티 설정, 쿠키 정책, 보안 정책, 캐시 정책, 백그라운드 전송 등을 세부적으로 설정할 수 있다.
- 그 종류는 뭐가 있을까?
- Shared Session
- 환경 설정의 기본!
- 다만, 너무 기본이라 completionHandler로만 데이터 처리가 가능하며, SessionDelegate를 사용할 수 없다.
- 그렇기 때문에 진행률을 보여주고자 한다면? DefaultSession으로 구현해야 한당.
- 백그라운드 전송은 지원하지 않는다.
- Default Session
- Shared와 마찬가지로 기본적인 설정을 말하며, Shared와 달리 커스터마이징이 가능하다.
- SessionDelegate를 통해 네트워크 응답에 대한 세부적인 제어가 가능하다! (shared는 불가능했음)
- Ephemeral Session
- Shared와 달리, 직접 생성할 수 있는 설정을 말하며 Shared와 비슷하지만 메모리에 처리된 데이터가 저장되지 않게끔 보안에 신경쓰고 싶을 때 사용한다!
- 쿠키, 캐시, 인증 정보 등을 기록하지 않는다. (= 프라이빗 기능을 구현할 때 사용된다!)
- 아마 은행쪽이나 결제쪽 통신을 할 때 자주 사용하지 않을까?
- Shared와 달리, 직접 생성할 수 있는 설정을 말하며 Shared와 비슷하지만 메모리에 처리된 데이터가 저장되지 않게끔 보안에 신경쓰고 싶을 때 사용한다!
- Background Session
- 영화를 다운받는 것 같이 큰 파일을 다운받을 때는 핸드폰을 켜놓고 그 화면을 기다리고 있는 게 아니라 백그라운드에서도 파일 작업이 진행되어야 할 것이다!! 그때 이 Session을 사용한다.
- 앱이 실행 중이지 않을 때(화면에 떠 있지 않는 상태일 때) 데이터를 다운로드하거나 업로드할 수 있다.
- Shared Session
- 이... 이게 몰까?
- 데이터 양에 따른 요청 리소스 응답
- 앞서 말한 Session들이 생성된 이후에는 Task를 생성하게 되는데, URLSession을 통해 생성되는 개별적인 데이터 요청을 task라고 한다.
- 기본적으로 openAPI 환경에서 통신하는 것은 리소스가 적게 들어가서 속도가 그렇게 오래 걸리지 않는다.
- 데이터를 전달하려는 방식과 구현하려는 목적에 따라서 우리는 task 타입을 설정해 주게 된다.
- 그 종류는 뭐가 있을까?
- dataTask
- 일반적으로 사용하는 방식을 말한다!
- uploadTask
- 영상을 업로드한다든가 데이터가 큰 영상을 보낼 때 사용한다.
- downloadTask
- dataTask에서 명시적으로 더 큰 단위의 데이터를 다운로드 받고 싶을 때 다운로드 테스크를 기반으로 요청하게 된다!
- streamTask
- 소켓 관련 통신을 할 때 사용한다.
- dataTask
- Request
- 네트워크 요청에 대한 정보를 표현하는 객체를 말하며, HTTP Header와 그 정책들을 캡슐화하여 요청하며, 어떤 데이터를 요청하는지에 대한 정보가 담겨있다.
- 네트워크에 정보를 요청하기 위해서는 URLSession이 필요하다! (request 하나만으로는 요청 불가)
- Response
- URL 데이터 요청의 응답에 대한 데이터를 말하며, 이 데이터를 처리할 수 있는 방법은 두 가지가 있다.
- Completion Handler
- Task가 종료된 시점에 실행되어 응답을 받을 수 있는 클로저를 말한다.
- 요청에 성공했을 때 response를, 실패했을 때 error값을 전달받는다.
- 따라서, 중간 단계에서 얼마나 진행되고 있는지를 알 수 없다.
- Session Delegate
- Task가 실행되는 동안 발생할 수 있는 상황에 세부적인 처리가 필요할 때 사용된다.
- 진행도나 큰 사진을 불러올 때, 그 진행도를 표시해 주기 위해서는 SessionDelegate를 사용해야 한다.
- 응답을 요청이 끝났을 때, 한 번 받는 CompletionHandler와 달리 서버로부터 최초 응답을 받은 이후로 서버로부터 데이터를 받을 때마다 다 받은 시점까지 원하는대로 이벤트 처리가 가능하다.
- Completion Handler
- URL 데이터 요청의 응답에 대한 데이터를 말하며, 이 데이터를 처리할 수 있는 방법은 두 가지가 있다.
URLSessionDelegate의 경우 이런 프로토콜로 구성되어 있어 사용할 경우 채택해 주어야 한다 ^_^ ...
아래는 간단한 예시이다!
func callRequest() {
// 첫 번째 필수 Method url / 두 번째 캐시 정책 / 세 번째 타임아웃인터벌(시간 설정)
// 네트워크 통신에서 응답이 너무 안 오면 사용자는 기다릴 수 없음 ㅡㅡ
// 걍 n초만 기다리다가 안 오면 다시 시도해달라고 하자!! => 기본으로 60초 가지고 있지만 보통 3~5초 정도로 사용함
guard let url = URL(string: "https://www.dhlottery.co.kr/common.do?method=getLottoNumber&drwNo=1079") else { return }
let request = URLRequest(url: url, timeInterval: 5)
// 5초 뒤에도 통신 안 오면 걍 안 온 걸루 처리함 ㅡㅡ
// 요청을 보내는 게 앞에 시작!!
// 어디를 보낼지에 대한 게 첫 번째 매개변수로 실행댐
// 응답 받고 나면 클로저 실행!!
// 클로저의 첫 번째 매개변수는 data 형식으로 매개변수 반환된다.
// 클로저 내부에서 받는 매개변수들은 모두 옵셔널로 정의되어 있는데
// data가 정상적으로 오게 된다면 error에서는 nil이, 반대라면 data와 response에서 nil이 나오기 때문이당.
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data else { return }
let value = String(data: data, encoding: .utf8)
// json 형태로 나오게 댐
print(value)
print(data)
// urlResponse를 알려주는 거잉
print(response)
print(error)
}.resume() // 네트워크 통신 시작!
}
}
completionHandler를 이용한 예시이다.
extension URLSessionViewController: URLSessionDataDelegate {
// 서버에서 최초로 응답받은 경우에 호출(상태코드 처리)
// 200~500까지 상태코드를 처리했던 것처럼 처리하는 게 필요함!!
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse) async -> URLSession.ResponseDisposition {
// response가 잘 왔는지 체크하고 상태코드 구성!!
print("RESPONSE", response)
if let response = response as? HTTPURLResponse, (200...500).contains(response.statusCode) {
// 이 헤더키에 있는 값을 가져오는 거잉
total = Double(response.value(forHTTPHeaderField: "Content-Length")!)!
// 이후 method들이 실행되도록 허락~
return .allow
} else {
// 이후 서버에서 데이터를 호출하는 경우에 대해서 미리 처리해 주는 거임
// 응답이 이상하게 됐을 때 이후 반복적으로 호출하거나 호출이 완료되었을 때 method가 실행되지 않도록!!
return .cancel
}
}
// 서버에서 데이터 받을 때마다 반복적으로 호출!!
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
print("Data:", data)
// buffer가 nil이면 append 구문 자체가 실행이 안 될 수 있음!!
buffer?.append(data)
}
// 서버에서 응답이 완료된 이후에 호출
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print("End")
if let error {
print(error)
} else {
guard let buffer = buffer else {
print(error)
return
}
imageView.image = UIImage(data: buffer)
}
}
}
위 코드는 이런 식으루 viewDidLoad에서 호출한다!
class ViewController: UIViewController {
var session: URLSession!
var total: Double = 0
var buffer: Data? {
// 프로퍼티 옵저버!!
didSet {
let result = Double(buffer?.count ?? 0) // total
if total == 0 {
progressLabel.text = "0%"
} else {
progressLabel.text = "\(Int(result / total * 100))%"
}
print(result, total)
}
}
... ...
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
// buffer?.append(data)가 실행되기 위함!!
// buffer가 nil이면 append가 실행되지 않으니까!
buffer = Data()
guard let url = URL(string: "https://apod.nasa.gov/apod/image/2308/M66_JwstTomlinson_3521.jpg") else { return }
// delegateQueue => delegateMethod 실행은 main에서 할 거라고 말하고 잇음 ..
// 만약에 이걸 global로 만들어놨다고 한다면 view 업데이트의 경우에는 메인에서 하는 걸 추가해야 했을 텐데 요기서는 지금 main에서 하고 잇음!!
session = URLSession(configuration: .default, delegate: self, delegateQueue: .main)
// 시작점과 끝점을 알 수 있도록!!
session.dataTask(with: url!).resume()
}
... ...
}
드문드문 잘라서 올린 거라 (...) 코드적으로 도움은 되지 않겠지만 ^_ ㅠ 일단 주석은 열심히 달아보았다
추후 괜찮은 예시가 생긴다면 깃헙 링크를 추가하도록 하겠다~~!
https://developer.apple.com/documentation/foundation/url_loading_system
URL Loading System | Apple Developer Documentation
Interact with URLs and communicate with servers using standard Internet protocols.
developer.apple.com
https://developer.apple.com/documentation/foundation/urlsession
URLSession | Apple Developer Documentation
An object that coordinates a group of related, network data transfer tasks.
developer.apple.com
https://developer.apple.com/documentation/foundation/urlrequest
URLRequest | Apple Developer Documentation
A URL load request that is independent of protocol or URL scheme.
developer.apple.com
https://developer.apple.com/documentation/foundation/urlsessiontask
URLSessionTask | Apple Developer Documentation
A task, like downloading a specific resource, performed in a URL session.
developer.apple.com
https://developer.apple.com/documentation/foundation/urlrequest
URLRequest | Apple Developer Documentation
A URL load request that is independent of protocol or URL scheme.
developer.apple.com
https://developer.apple.com/documentation/foundation/urlresponse
URLResponse | Apple Developer Documentation
The metadata associated with the response to a URL load request, independent of protocol and URL scheme.
developer.apple.com
'iOS > App' 카테고리의 다른 글
[iOS] NavigationBar BackgroundColor 노치까지 채우기 (0) | 2023.12.02 |
---|---|
[RxSwift] Single (1) | 2023.11.21 |
[iOS] Push Notification 보내기 (1) | 2023.11.13 |
[CoreLocation] Location (1) | 2023.08.28 |
[iOS] Notification (2) | 2023.08.21 |