URLSession
An object that coordinates a group of related, network data transfer tasks.
네트워크 데이터 전송 작업과 관련된 그룹을 조정하는 객체. 라고 공식문서에 나와있듯이 이제 API를 통해 데이터를 주고 받으려면 서버와 통신할 수 있어야 합니다. 이를 가능토록 하는 게 URLSession이라고 할 수 있습니다 !
이 URLSession을 통해서 어떻게 앱과 데이터를 주고받는지에 대한 방식은 일단 두가지. 비교적 전에 쓰던 Completion Handler 패턴, 그리고 이보다 최근에 나온 Swift Concurrency를 이용한 방식이 있는데... 일단 이것들을 다루기 전에 이 안에선 어떻게 해야 URLSession을 가지고 데이터들을 불러올 수 있을지에 대해 알아보도록 하겠읍니다.
일단 URLSession에서 큰 개념 두가지! URLSessionConfiguration과 URLSessionTask.
URLSessionConfiguration
세션의 동작 방식을 구성하는 설정 객체
- default: 기본 구성, 디스크 캐싱 지원
- ephemeral: 캐시, 쿠키 등을 저장하지 않는 임시 세션 (애플 개인정보 보호 모드같은..!)
- background: 앱이 백그라운드에 있을 때도 네트워크 작업을 계속할 수 있음
URLSessionTask
실제 네트워크 작업을 수행하는 태스크 객체
- URLSessionDataTask: 데이터를 메모리에 받는 일반적인 HTTP 요청
- URLSessionDownloadTask: 파일 다운로드를 위한 태스크
- URLSessionUploadTask: 파일 업로드를 위한 태스크
- URLSessionWebSocketTask: WebSocket 통신을 위한 태스크(iOS 13+)
뭐 그밖에도 일단 알아야 될 부분들을 말하자면
URL 객체, URLRequest 객체 !!
결국 우린 허공에 대고 데이터 보내주세요~하고 네트워킹하는게 아니기 때문에 데이터를 보내달라고 할 곳이 필요합니도
이를 우린 해당 자원이 있는 주소인 url을 가지고 swift 프레임워크 안에 있는 URL 객체로 넣어서 만들고 이를 가지고 URLRequest라는 객체를 만들 것입니다 ~
자 일단 !! 제일 기초적인 get 요청부터 어떻게 할지 알아보도록 해요 (get은 해당 url에 대고 서버한테 나 이 데이터 좀 보내주셈!!하는거라고 이해하면 됩니다, 모르면 RESTFUL API 한번 슥 훑어보고 오십쇼)
일단 하면서 만들어야하는 준비물을 대충 말해보자면,
- URL - 어느 주소에 있는 자원에 접근할 수 있게 이를 swift에서 쓰려면 객체로 만들어야됨 !!
- URLSession - 요 부분은 따로 configuration을 입혀줘도 되고 자체 제공되는 URLSession.shared로 접근해도 됨!! 이거 많이 쓰임
- URLConfiguration - URLSession에다가 네트워크 작업할때 세션이 어떻게 동작할지에 대한 방식을 여기서 넣어준다고 했죠?
- URLRequest - 저희가 실제로 이 세션이 작업을 할 수 있게 명령해줄 때 필요한 요구사항임. 요 request에 위에서 말한 URL 객체를 넣고 .. get말고도 다른 작업을 할거면 지정해줄 수 있고 다양한 설정들을 해줄 수 있음. 요청 보낼때 이거 참고해주세요 !! 하는 Header라는 것도 넘겨줄 수 있고, 이 Request도 정말 많이 씁니다.
- URLSessionTask - 앞서 관련된 요구사항들을 미리 설정해두고 이를 가지고 이제 요청을 해야 되잖아요? 앞에서 정의해둔 요구사항 가지고 실제 작업을 하도록 하는게 이 URLSessionTask. 데이터를 받아올 수도 있고 뭐 다운로드 등등 다양한 작업이 있읍니다..^^*
그래서 이 준비물을 어떤식으로 꺼내 쓰냐!?
보통 크게 봤을 때 URL 만들어주고 이거가지고 URLRequest를 만들어줍니다. 요구사항 만들어주고, 이걸 가지고 써야하니깐 가장 큰 개념인 Session을 만들어줘요(필요하다면 configuration에 추가 설정 넣고!). 그 담에 이 요구사항과 세션을 가지고 실제 작업을 한다!
사실 순서는 앞쪽은 크게 상관없음. request보다 세션을 먼저 만들어줘도 쨋든 둘다 쓸거니깐 문제 없게 알아서 만들면 되고..
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
}
// 서버 데이터를 불러오는 메서드 선언
private func fetchData() {
guard let url = URL(string: "https://reqres.in/api/users/1") else {
print("URL이 올바르지 않습니다")
return
}
// URLRequest 설정
var request = URLRequest(url: url)
// GET 메소드 사용
request.httpMethod = "GET"
// URLSession 생성 (공유 세션 사용)
let session = URLSession.shared
// dataTask
session.dataTask(with: request) { (data, response, error) in
// 에러 체크
if let error = error {
print("네트워크 오류: \(error.localizedDescription)")
return
}
// HTTP 응답 체크
guard let httpResponse = response as? HTTPURLResponse else {
print("HTTP 응답이 아닙니다")
return
}
let successRange = 200..<300
// 상태 코드 체크
print("상태 코드: \(httpResponse.statusCode)")
if !successRange.contains(httpResponse.statusCode) {
print("요청 실패: 상태 코드 \(httpResponse.statusCode)")
return
}
// 데이터 체크
guard let data = data else {
print("데이터가 없습니다")
return
}
// 디코딩
do {
let userInfo = try JSONDecoder().decode(ResponseData.self, from: data)
print(userInfo)
// UI 업데이트는 메인 스레드에서 수행
DispatchQueue.main.async {
// UI 업데이트 코드
}
} catch {
print("JSON 디코딩 오류: \(error.localizedDescription)")
}
}.resume()
}
}
이게 뭐지....하고 바로 눈 돌렸던 URLSession 첨볼때의 제 자신..
일단 다 한번에 집어넣으려하면 배탈나니깐 실제 URLSession 관련 작업들을 수행하는 fetchData() 메서드를 뜯어봅시다 ~!
아까 말했듯 URL을 만든다고 했어요
guard let url: URL = URL(string: "https://reqres.in/api/users/1") else {
print("URL is not correct")
return
}
우린 보통 주소를 가져다가 쓰겠죠? 뭐 users/뒤에 있는 1같은경우 메서드 파라미터로 받아와서 2나 3같은 다른 값을 넣어줄수도 있는거고 쨋든, 이 주소가지고 URL을 생성해줍니다. 근데 이 URL을 단순히 만들게 되면
옵셔널로 줘요. 이를 언래핑 해줘야하니 guard let을 쓰면서 URL 객체를 넣어주는 것 !
근데 이 변환 과정에서 언래핑이 안되면 URL 객체를 생성하는 과정에서 문제가 있다는거겠죠? 그럼 else 타고 들어가서 return으로 그 흐름을 끊습니다.
쨋든 URL을 만들었으니 URLRequest를 이거가지고 만들면 됩니다.
// URLRequest 설정
var request: URLRequest = URLRequest(url: url)
// GET 메소드 사용
request.httpMethod = "GET"
일단 기본적으로 URLRequest 생성시엔 url을 받게 되어있는데 위에서 만들었던 url 객체를 넣어주면 됩니다.
그리고 아까 말했듯 다양한 설정을 해줄 수 있는데 여기선 이 네트워킹 메서드로 get을 쓴다고 말해주는 것!
// URLSession 생성 (공유 세션 사용)
let session = URLSession.shared
그 담엔 아까 말했던 것 처럼 URLSession을 만들어주는데, 이미 shared라는 걸 쓸 수 있으니 가져다 씁니다.
session.dataTask(with: request) { (data, response, error) in
그 다음 줄 보면 이제 task를 처리하도록 명령합니다. 근데 뒤에 있는 (data, response, error) in은 뭐냐면
completionHandler라는건데 해당 작업이 끝나면 저 자원들을 가지고 어느 작업을 수행하겠다! 정도로 이해하면 될 것 같아요
data은 Data?타입이고 서버로부터 받은 실제 데이터를 가지고 있고,
response는 URLResponse? 타입으로 보통 HTTP 프로토콜에 특화된 추가 정보를 포함하는 HTTPURLResponse라는 타입으로 캐스팅해서 씁니다. 이는 상태코드(statusCode)와 응답 헤더(Content-Type, Content-Length, Authorization 등)이 있어요.
Error는 말그대로 어떤 오류가 있는지 담겨있읍니다.
// 에러 체크
if let error = error {
print("네트워크 오류: \(error.localizedDescription)")
return
}
// HTTP 응답 체크
guard let httpResponse = response as? HTTPURLResponse else {
print("HTTP 응답이 아닙니다")
return
}
let successRange = 200..<300
// 상태 코드 체크
print("상태 코드: \(httpResponse.statusCode)")
if !successRange.contains(httpResponse.statusCode) {
print("요청 실패: 상태 코드 \(httpResponse.statusCode)")
return
}
// 데이터 체크
guard let data = data else {
print("데이터가 없습니다")
return
}
내부를 보면 error가 있는지 확인하고 없으면 response를 HTTPURLResponse로 타입 캐스팅하도록 합니다.
이 과정에서 실패한다하면 response가 HTTP 응답이 아니니 return되도록 하고.
이 과정도 통과를 한다면 보통 HTTP 성공 코드 범위인 200에서 299까지 현재 응답받은 statusCode가 있는지! 확인합니다.
즉 성공 여부를 보게 되는 과정이고, 이 과정도 통과했을 때 실제 데이터가 실려 왔는지 guard let data로 확인합니다.
(guard let data = data는 guard let data로 축약가능)
// 디코딩
do {
let userInfo = try JSONDecoder().decode(ResponseData.self, from: data)
print(userInfo)
// UI 업데이트는 메인 스레드에서 수행
DispatchQueue.main.async {
// UI 업데이트 코드
}
} catch {
print("JSON 디코딩 오류: \(error.localizedDescription)")
}
이제 문제 없다는 걸 알았으니 기존에 만들어두었던 틀에다가 decode해줍니다. 데이터들을 맞춰 넣어서 쓸 수 있게 !!
일단 가볍게 get 요청을 할 수 있는 정도까지 알아보는걸로..!!
'iOS > Swift' 카테고리의 다른 글
[TIL / 25.05.08] RxSwift.. 처음 공부해볼게요 1 (0) | 2025.05.08 |
---|---|
[WIL / 25.05.06] 8~9주차 회고 및 To-do (2) | 2025.05.06 |
[TIL / 25.04.16] Lv3 서치바 관련 트러블슈팅 기록 (0) | 2025.04.16 |
[TIL / 25.04.11] UICollectionView Compositional Layout 1 (0) | 2025.04.11 |
[TIL / 25.03.31] 앨범에서 사진 고르고 잘라서 쓸 수 있도록! (feat. PHPickerViewController, TOCropViewController) (1) | 2025.03.31 |