[내일배움캠프 7주차 (02/12)]

yeseul jang·2026년 2월 12일

내일배움캠프

목록 보기
12/32

📌 네트워크

🔎 API(Application Programming Interface)

  • 프로그램과 프로그램이 소통하기 위한 규칙(인터페이스)
  • 요청하는 방법과 응답 형식을 정해놓은 설명서
  • 내부 구현을 몰라도 사용 가능하고 유지보수 쉬움

🔎 URL 구조

  • URL(Uniform Resource Locators): 웹에서 특정 위치를 나타내는 주소
  • protocol: http, https - 인터넷 통신 규약을 의미
  • Domain: 자원이 위치한 서버의 이름, url의 정체성
  • Port: 어떤 서버를 이용할지 번호로 결정 (http - 80, https - 443)
  • Path: 서버에서 제공하는 자원의 경로를 나타냄
  • Query: 자원에 대한 추가적인 매개변수를 전달하는 데 사용됨. 주로 key=value 형식(여러개일 경우 &)
  • Fragment: 자원내에서 특정 부분 가리킴

🔎 REST API (Representational State Transfer)

  • 전세계에서 대표적으로 널리 쓰이는 API 형식 중 하나.
  • 상태 (State) 를 표현해서 정보를 주고 받는 API 이다.
  • HTTP URL 을 통해서 자원을 명시한다.
  • HTTP Method (GET, POST, PUT, DELETE 등) 를 통해 해당 자원을 어떻게 할 것인지 CRUD 를 결정한다.
    • GET: 자원을 조회
    • POST: 자원을 생성
    • PUT: 자원을 업데이트
    • DELETE: 자원을 삭제
  • REST API 도 결국 API 이기 때문에, 데이터를 주고 받는 형식, 창구라고 생각 할 수 있음.

📌 URLSession

  • URLSession은 네트워크 통신을 담당하는 Apple의 기본 클래스
  • iOS는 기본적으로 HTTP 요청을 직접 처리하지 않고 네트워트 매니저인 URLSession가 처리
URLSessionURLSessionTask
   ↓
dataTask / uploadTask / downloadTask

🔎 코드

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        fetchData()
    }
    
    // 서버 데이터를 불러오는 메서드 선언
    private func fetchData() {
        
        // 리소스 URL 단순문자열이 아니라 유효한 형식인지 검증된 객체라서 옵셔널임,
        // 리소스의 위치를 나타내는 객체
        guard let url: URL = URL(string: "https://reqres.in/api/users/1") else {
            print("URL is not correct")
            return
        }
        
        // URLRequest 설정 - 어떤 요청을 보낼 것인가를 정의
        var request: URLRequest = URLRequest(url: url)
        
        // GET 메소드 사용 (GET, POST, PUT - 수정, DELETE)
        request.httpMethod = "GET"
        
        // json 데이터 형식임을 나타냄,
        // HTTP Header는 이 요청의 부가 정보, Content-Type는 내가 보내는 데이터 형식
        // GET 요청이라 body가 사실 필요없음
        // GET일 때 Content-Type 안 붙이는 경우 많음
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        // URLSession 생성 - 네트워크 환경을 관리하는 객체 (기본 default 세션)
        // configuration 종류
        let session: URLSession = URLSession(configuration: .default)

        // dataTask
        session.dataTask(with: request) { (data, response, error) in
                // http 통신 response 에는 status code 가 함께오는데, 200번대가 성공을 의미.
            let successRange: Range = (200..<300)
            
            // 에러 + 데이터 체크
            guard let data, error == nil else { return }
            
            // 타입캐스팅 response는 URLResponse 타입, HTTP 정보를 보려면 HTTPURLResponse로 다운캐스팅해야함
            if let response: HTTPURLResponse = response as? HTTPURLResponse{
                print("status code: \(response.statusCode)")
                
                // 요청 성공 (StatusCode가 200번대)
                if successRange.contains(response.statusCode){
                    
                    // 요청 성공하면 decode하겠다.
                    guard let userInfo: ResponseData = try? JSONDecoder().decode(ResponseData.self, from: data) else { return }
                    print(userInfo)
                    
                } else { // 요청 실패 (Status code가 200대 아님)
                    print("요청 실패")
                }
            }
            
        }.resume()
    }
}

🔎 async/await 적용

📍 코드

// async - 이 함수는 중간에 멈출 수 있는 함수(이 안에서는 await을 쓸 수 있음)
    private func fetchData2() async {
        
        // URL 객체 생성(실패가능성 있으니 옵셔널)
        guard let url: URL = URL(string: "https://reqres.in/api/users/1") else {
            print("URL is not correct")
            return
        }
        
        // URLRequest 생성 - 요청 정보 설정
        var request: URLRequest = URLRequest(url: url)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        
        // 세션 생성 - 네크워트 환경 관리자 생성
        let session: URLSession = URLSession(configuration: .default)
        
        do {
            // await - 이 작업이 끝날때 까지 기다리지만 스레드는 점유 ㄴㄴ
            // 네트워크 요청 시작하고 서버 응답 기다림 / 이 함수는 suspend 상태 / 현재 스레드는 다른 작업중 /
            // 응답 도착하면 함수가 resume됨 / data와 response 반환
            let (data, response) = try await session.data(for: request)
            let successRange: Range<Int> = (200..<300)
            guard let response: HTTPURLResponse = response as? HTTPURLResponse else { return }
            
            print("status code: \(response.statusCode)")
            
            if successRange.contains(response.statusCode) {
                
                guard let userInfo: ResponseData = try? JSONDecoder().decode(ResponseData.self, from: data) else { return }
                print(userInfo)
                
            } else {
                print("요청 실패")
            }
            
        } catch {
            print(error)
        }
    }

📍 동기(Synchronous)/비동기(Asynchronous)

  • 동기(Synchronous): 한 작업이 끝날 때까지 다음 코드가 실행되지 않는 방식
  • 비동기(Asynchronous): 작업을 시작만 해두고, 끝날 때까지 기다리지 않고 다음 코드를 실행하는 방식

📍 왜 네트워크는 비동기?

  • 시간이 오래걸려서 이걸 동기로 하면 UI가 멈춰서 사용자는 앱이 죽었다고 생각할 수 있음

📍 async/await

  • 복잡한 비동기 코드를 읽기 쉽고 안전하게 만드는 문법(비동기를 동기처럼 읽을 수 있게 해줌)
  • 비동기 함수는 실행도중에 일시 중단(suspend) 될 수 있는 함수
  • suspend(일시 중단)은 스레드를 멈춘다는 뜻이 아니고 현재 함수의 실행만 잠시 멈추고, 스레드는 다른 일을 하게 둠 -> 이게 async

📍 비교

  • 클로저 방식: 요청 시작 - 완료 시 클로저 실행 - 콜백 기반
  • async 방식: Swift Concurrency 런타임이 Continuation 객체를 만듦 - 함수 실행 상태를 저장 - 응답 오면 이어서 실행

📍 Task 호출

Task는 Swift Concurrency 런타임에 등록되는 작업 단위
생성되면 즉시 실행을 예약 시스템이 적절한 스레드에 배치
현재 스레드를 점유하지 않음
Task{} 자체는 실행 예약이라 언제 실행될지는 보장하지 않음

  • 기본
Task {
    await fetchData()
}
  • MainActor에서 실행: @MainActor
Task { @MainActor in
    label.text = "완료"
}
  • 우선순위 지정(.high,.medium,.low,.background)
Task(priority: .high) {
    await fetchData()
}
  • 이미 async 함수 안이면 Task 필요 없음
func anotherFunction() async {
    await fetchData()
}

📍 주의점

func test() async {
    await fetchData()
    print("끝")
}
  • 이런 경우 fetchData 끝난 후 "끝" 출력
  • 같은 async 컨텍스트 안에서 기다리기 때문에

📌 do/try/catch

  • 실패할 수 있는 코드는 반드시 표시해야함

  • throws: 이 함수는 에러를 던질 수 있음

  • try: 에러 발생 가능

  • do: 에러 감싸는 블록

  • catch: 에러 잡기

  • try 종류
    - try: 반드시 처리
    - try?: 실패 시 nil
    - try!: 실패하면 크래시

profile
iOS 개발

0개의 댓글