• Feed
  • Explore
  • Ranking
/
/
    💻 Dev

    비동기 프로그래밍의 이해

    iosSwift
    지
    지성
    2025.02.19
    ·
    5 min read

    비동기 프로그래밍이란?

    동기(Synchronous) vs 비동기(Asynchronous) 프로그래밍

    동기(Synchronous) 프로그래밍

    • 하나의 작업이 끝날 때까지 다음 작업을 실행하지 않음

    • 작업이 완료될 때까지 앱이 멈춘 것처럼 보일 수 있음

    print("작업 시작")
    sleep(3) // 3초 동안 멈춤
    print("작업 완료")

    문제점

    • sleep(3) 동안 다른 작업을 할 수 없음

    • 네트워크 요청 같은 작업이 오래 걸리면 UI가 멈출 수 있음

    비동기(Asynchronous) 프로그래밍

    • 작업을 백그라운드에서 실행하고 완료될 때까지 기다릴 필요 없음

    • UI가 멈추지 않고 사용자 경험이 개선됨

    print("작업 시작")
    
    DispatchQueue.global().async {
        sleep(3)
        print("작업 완료")
    }
    
    print("다른 작업 실행 가능!")
    
    // 작업 시작
    // 다른 작업 실행 가능!
    // (3초 후) 작업 완료

    Swift에서 비동기 처리하는 방법

    GCD(Grand Central Dispatch) – DispatchQueue 사용

    iOS에서는 GCD를 사용해 멀티스레딩을 쉽게 구현할 수 있다.

    DispatchQueue.global(qos: .background).async {
        // 백그라운드에서 실행 (예: 네트워크 요청)
        print("백그라운드 작업 실행")
    
        DispatchQueue.main.async {
            // UI 업데이트 (메인 스레드에서 실행)
            print("UI 업데이트")
        }
    }

    사용되는 큐의 종류

    1. DispatchQueue.global(qos: .background) → 백그라운드 작업

    2. DispatchQueue.global(qos: .userInitiated) → 사용자 요청 처리

    3. DispatchQueue.main → UI 업데이트

    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        print("2초 후 실행됨")
    }

    OperationQueue 사용

    GCD보다 더 객체지향적으로 비동기 작업을 처리할 수 있다.

    let queue = OperationQueue()
    
    queue.addOperation {
        print("백그라운드 작업 실행")
        
        OperationQueue.main.addOperation {
            print("UI 업데이트")
        }
    }

    GCD보다 유연한 작업 제어 가능

    • 작업 간 의존성 설정 가능

    • 특정 작업을 취소하거나 일시 중지 가능

    async/await 사용 (Swift 5.5 이상)

    비동기 코드의 가독성을 높이는 최신 문법

    func fetchData() async {
        print("데이터 요청 시작")
        try? await Task.sleep(nanoseconds: 2_000_000_000) // 2초 대기
        print("데이터 받아옴")
    }
    
    Task {
        await fetchData()
    }

    비동기 코드를 동기 코드처럼 읽기 쉽게 작성 가능

    네트워크 요청에서 비동기 프로그래밍 활용하기

    전통적인 URLSession 방식

    콜백 방식이라 코드가 복잡해질 수 있다.

    let url = URL(string: "https://api.example.com/data")!
    
    URLSession.shared.dataTask(with: url) { data, response, error in
        if let data = data {
            print("데이터 크기: \(data.count) bytes")
        }
    }.resume()

    async/await을 활용한 네트워크 요청 (Swift 5.5 이상)

    코드가 간결하고 가독성이 좋다.

    func fetchData() async throws -> Data {
        let url = URL(string: "https://api.example.com/data")!
        let (data, _) = try await URLSession.shared.data(from: url)
        return data
    }
    
    Task {
        do {
            let data = try await fetchData()
            print("데이터 크기: \(data.count) bytes")
        } catch {
            print("에러 발생: \(error)")
        }
    }

    비동기 프로그래밍 사용 시 주의점

    UI 업데이트는 항상 메인 스레드에서 실행해야 함

    백그라운드 작업이 끝난 후 UI를 변경하려면 DispatchQueue.main.async를 사용

    DispatchQueue.global().async {
        let data = fetchData()
        
        DispatchQueue.main.async {
            label.text = "데이터 업데이트 완료"
        }
    }

    네트워크 요청 시 에러 처리를 반드시 추가해야 함

    do {
        let data = try await fetchData()
        print("데이터 로드 성공")
    } catch {
        print("네트워크 요청 실패: \(error)")
    }

    메모리 관리 주의 – 강한 참조 순환 방지

    weak self를 사용해 메무리 누수 방지

    class ViewController: UIViewController {
        func loadData() {
            Task { [weak self] in
                guard let self = self else { return }
                let data = try await fetchData()
                print("데이터: \(data)")
            }
        }
    }






    - 컬렉션 아티클