서버와의 데이터 전달 , REST API를 이용한 통신을 말함
URLSession : Apple의 Foundation프레임워크에서 제공하는 클래스로 네트워크 통신
→ 이 글에서는 URLSession에 대한 공부 및 정리
RxSwift : ReactiveX(Reactive Extensions) 라이브러리의 Swift 버전
→ 나중에 다룰 예정
Combine : iOS 13부터 도입한 공식적인 리액티브 프로그래밍 프레임워크
→ 나중에 다룰 예정
API 엔드 포인터와 함께 특정 자원에 대한 요청 식별 및 전달 → 즉 데이터 통신을 위해 필요한 자원

통신 클라이언트와 서버간의 통신규약
서버가 이름을 가진다면 해당요소가 이름을 의미한다고 생각하면 된다
API 요청을 수신하는데 사용되는 포트
원하는 데이터 자원 및 서비스의 위치를 나타냄
ex) /auth/signup → 유저의 회원가입을 의미
서버에서 데이터를 어떻게 전달할지 어떻게 받을지에 대한 옵션을 생각하면 된다

HTTP 프로토콜 기반으로 클라이언트와 서버간의 통신 규약의미
데이터베이스의 CRUD를 안다면 이해가 쉬움
Read, 말그대로 데이터를 읽는다
ex) 유저의 이름을 조회한다
Create, 데이터를 생성
ex) 회원가입
Update : 기존 데이터를 수정
ex) 유저의 닉네임을 변경
Delete : 데이터 삭제
자원을 찾을수 있는 주소를 나타낸다.
REST API에서는 모든 데이터가 자원으로 표현
ex) 사용자 이름, 나이, 성별, 프로필 이미지 드등
네트워크 데이터를 가져오거나 보내는 작업 수행
UI 블로킹 : UI는 메인스레드에서 작업을 수행하는데 네트워크 호출이 완료될때까지 App이 작동을안하고 멈추게됨
→ 쉽게 설명하자면 데이터를 다전달받기전까지 앱의 화면이 나오지않는다는 말, 경험상으로 제대로 처리 하지 못하면 앱이 멈추거나 종료된다
성능저하
데드락 위험

private func fetchRemoteProduct(){
let productID = Int.random(in: 1 ... 100)
if let url = URL(string: "https://dummyjson.com/products/\(productID)"){
let task = URLSession.shared.dataTask(with: url) { data, response, err in
if let err = err{
print("Error:\(err)")
}else if let data = data{
do{
let product = try JSONDecoder().decode(RemoteProduct.self, from: data)
self.currentProduct = product
print(self.currentProduct)(1)
}catch{
print("Decode Error:\(String(describing: err))")
}
}
}
task.resume()
}
}
**Optional(URLSessionStudy.RemoteProduct(id: 17, title: "Tree Oil 30ml",
description: "Tea tree oil contains a number of compounds,
including terpinen-4-ol, that have been shown to kill certain bacteria,",
price: 12.0, thumbnail: https://i.dummyjson.com/data/products/17/thumbnail.jpg))**
import Foundation
// URLSession 인스턴스 생성
let session = URLSession.shared
// URL 생성
if let url = URL(string: "https://api.example.com/data") {
// URLSessionDataTask를 사용하여 비동기적으로 데이터 요청
// URLRequest 생성
var request = URLRequest(url: url)
// HTTP 메서드 설정 (POST)
request.httpMethod = "POST" // GET / PUT / DELETE 사용 가능
// HTTP 헤더 설정
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
// HTTP Body에 보낼 데이터 설정 (JSON 형식)
let parameters: [String: String] = [
"value1": "example value",
"value2": "example value"
// 추가적인 필요한 데이터 추가 가능
]
// HTTP Body에 JSON 데이터 설정
request.httpBody = try? JSONEncoder().encode(parameters)
let task = session.dataTask(with: request) { (data, response, error) in
if let error = error {
print("Error: \(error)")
} else if let data = data {
// 데이터를 받아온 후 처리하는 로직을 작성
print("Received data: \(data)")
}
}
// 네트워크 요청 시작
task.resume()
}
데이터를 객체로 디코딩할때 사용
**CodingKeys** 예시struct User: Decodable {
let id: Int // 디코딩할 프로퍼티
let name: String // 디코딩할 프로퍼티
~
public enum CodingKeys: String, CodingKey {
case id = "key"
case name
}
// Decoding - 디코딩
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
}
}
서버에서 불러온 데이터 이름을 내가 원하는 이름으로 변경하고 싶을때
CodingKeys를 사용하면 된다
객체를 데이터로 인코딩할 때사용
struct User: Encodable {
let id: Int
let name: String
// 다른 프로퍼티들...
public enum CodingKeys: String, CodingKey {
case id = "key"
case name
}
// Encodable 프로토콜을 준수하기 위한 커스텀 인코딩 로직
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
// 다른 프로퍼티들도 인코딩 가능
}
}
두 가지 하위 프로토콜
**Encodable**과Decodable을 결합
외부 데이터(JSON)를 Swift의 데이터 모델로 변환,Swift의 데이터 모델을 외부 데이터로 변환을 모두 수행해야 할때 사용가능
→ 쉽게 설명하면 서버에서 데이터 불러오고 보내는것을 둘다 할경우에 사용한다고 생각하면 된다.
struct User: Codable {
let id: Int
let name: String
// 다른 프로퍼티들...
public enum CodingKeys: String, CodingKey {
case id = "key"
case name
}
// Encodable 프로토콜을 준수하기 위한 커스텀 인코딩 로직
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
// 다른 프로퍼티들도 인코딩 가능
}
// Decoding - 디코딩
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
}
}