3월 14일 TIL (비동기 및 네트워킹)

이승원·2024년 3월 14일
0

TIL

목록 보기
44/75
post-thumbnail

Thread (쓰레드)?

  • Thread 는 컴퓨터 프로세스 내에서 실행되는 실행 흐름의 단위다.
  • 프로세스 Process 는 운영체제로부터 자원을 할당받아 실행 중인 프로그램의 인스턴스를 나타내는, 각각의 프로세스는 하나 이상의 쓰레드를 갖을 수 있다.
  • Swift 에서의 Thread 종류
    • 메인 쓰레드 (Main Thread) : 애플리케이션의 주요 인터페이스 UI 및 UI 업데이트를 담당하느 스레드입니다. UI 요소의 변경은 메인 스레드에서 수행되어야 합니다.
    • 백그라운드 쓰레드 (Background Thread) : 메인 스레드 이외에 동시에 작업을 수행하기 위해 생성되는 스레드들을 말한다. 주로 작업을 분산하거나 병렬로 처리할 때 사용된다.

비동기 (Asynchronous)?

동기 (synchronous) vs 비동기 (Asynchronous)

  • 동기 Sync : 작업이 순차적으로 실행되는 것을 의미한다. 하나의 queue 처럼 FIFO 방식으로 작동된다고 생각하면 된다.
  • 비동기 Async : 작업이 별도의 쓰레드 또는 백그라운에서 실행되며, 다른 작업을 기다리지 않고 동시에 실행된다. 작업이 완료되면 콜백 (Callback) 혹은 완료 핸들러 (Completion Handler)를 통해 결과를 처리한다. 메서드 호출 순서대로 작업이 완료된다는 것을 보장하지 않는다. 자동으로 Thread Scheduling을 통해 최적의 성능을 보장한다고 한다. [공식문서]


직렬 (Serial) vs 동시 (Concurrent)

  • 직렬 Serial : 분산처리 시킨 작업을 오직 한 개의 쓰레드에서만 처리하는 것이다. 예를 들면, A 쓰레드에서 4개의 작업을 분산처리 했는데, 4개의 작업 모두 하나의 같은 쓰레드 B에서만 처리하는것이다.
  • 동시 Concurrent : 몇개의 쓰레드로 분산할지는 시스템이 정하여 여러개의 쓰레드로 분산 처리 하는 것. 작업들이 유가한 작업 일수록 유용하다.

DispatchQueue

  • GCD ( Grand Central Dispatch ) : Apple 플랫폼에서 멀티스레드 프로그래밍을 간단하고 효율적으로 구현하기 위한 기술이다. GCD는 다양한 작업을 관리하고 실행하기 위한 API를 제공하고 병렬성을 활용할 수 있게 한다.

GCD (Grand Central Dispatch) 의 특징

  1. Queue : GCD는 큐를 사용하여 작업을 관리하고, 세분화하고, 실행할 큐에 따라 작업의 속성이 결정할 수 있다.
  2. 간편한 비동기 작업 처리 : GCD를 사용하면 비동기적으로 작업을 수행할 수 있다. 개발자가 따로 쓰레드를 관리 해주지 않아도 되게끔 작동한다.
  3. Queue의 종류에 따라서 다른 동작 방식: Serial Queue, Concurrent Queue, 앞서 말한 직렬 및 동시의 특징에 따른 Queue가 존재한다.
  4. 콜백 사용
  5. QoS ( Quality of Service ) 지원 : GCD는 각 큐에 대한 우선순위 설정을 지원하여 시스템이 작업을 최적의 성능을 유지하며 진행할 수 있도록 한다.

DispatchQueue.main vs DispatchQueue.global()

  • main 쓰레드는 UI를 담당하는 쓰레드이며, 사용자 인터페이스 및 상호작용을 처리하는 쓰레드이다. 따라서 오래 걸리는 작업을 main 쓰레드에서 진행할 경우, 앱이 멈추거나 끊기는 현상을 볼 수 있다.
  • 반명 global은 전역(백그라운드) 스레드이기 때문에, 오래 걸리는 작업을 global에서 처리하여 콜백을 통해 main Thread로 넘겨주는 작업을 주로한다.
  • DispatchQueue.global()은 기본적으로 Concurrent 방식이고, Main은 Serail 방식이다.
  • 전역 DispatchQueue에서 async sync를 사용하여 작업을 추가하면, 해당 작업은 백그라운에서 실행된다.
  • 신기한건(?) swift에서는 Thread Scheduling 에 대해서 사용자는 알 수 있는 방법이 없다고 한다. (DispatchQueue를 사용한다면)
  • 예시 코드 :
import Foundation

DispatchQueue.global().sync {
    print("Synchronous Task")
}

// 비동기적으로 실행되는 작업
DispatchQueue.global().async {
    print("Asynchronous Task")
}

// 백그라운드에서 비동기 작업 실행
DispatchQueue.global().async {
    // 여기서 백그라운드에서 실행될 작업을 수행합니다.
    for i in 1...5 {
        print("Background Task \(i)")
        print("Current Thread: \(Thread.current)")
    }
    
    // 작업이 완료되었음을 메인 스레드로 알립니다.
    DispatchQueue.main.async {
        print("Background Task Completed, Updating UI")
        // UI 업데이트 등을 수행할 수 있습니다.
    }
   
}

print("Hello")

네트워킹 (Networking)

  • swift에서의 네트워킹은 주로 URLSession을 사용하여 수행된다.
  • 네트워킹은 주로 외부 서버 또는 인터넷 리소스와 데이터를 주고 받는 작업이며, 네트워크 환경에 따라서 작업 소요시간이 달라지기 떄문에, 주로 비동적인 방식으로 처리하는 것이 일반적이다.
  • 아래 예시 코드를 통해 더 자세히 알아보자
import Foundation

// 네트워크 작업을 처리할 함수
func fetchData() {
    if let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1") {
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            // 네트워크 작업 완료 후 실행될 코드 (비동기적으로 실행)
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }
            
            if let httpResponse = response as? HTTPURLResponse {
                print("Status code: \(httpResponse.statusCode)")
            }
            
            if let data = data {
                do {
                    // JSON 데이터 파싱
                    let json = try JSONSerialization.jsonObject(with: data, options: [])
                    if let jsonDict = json as? [String: Any] {
                        // 파싱된 데이터 활용
                        print("Received JSON data: \(jsonDict)")
                    }
                } catch {
                    print("JSON parsing error: \(error.localizedDescription)")
                }
            }
        }
        
        task.resume() // 네트워크 작업 시작 (비동기적으로 실행됨)
    }
}

// fetchData 함수 호출
fetchData()
  1. fetchDate() 함수를 선언한다.
  2. 주소를 URL 타입으로 타입캐스팅을 한다.
    • 영어나 특수한 문자만 사용 가능하고, 한글이나 공백을 포함시 nil을 리턴한다.
    • URL에 한글이나 공백이 있을 경우, String.addingPercentEncoding을 통해 변환을 해야한다.
  3. URLSession.shared.dataTask 을 분리해서 해석을 하자면
    • URLSession : iOS 또는 MacOS에서 네트워크 통신을 처리하기 위한 API
    • URLSession.shared : 기본 URLSession 인스턴스를 반환하는 프로퍼티. 해당 인스턴스는 전역에서 공유되는 객체로, 네트워크 작업을 수행하기 위해 사용된다.
    • URLSession.shared.dataTask(with:completionHandler:): URLSession 객체의 메서드로, 지정된 URL에서 데이터를 가져오는 비동적인 작업을 생성한다. with: 매개 변수는 URL을 나타내고, completionHandler: 는 작업이 완료 되었을때 호출되는 클로저다.
    • 따라서 해당 코드는 URLSession의 전역 공유 인스턴스를 생성하여, 지정된 URL에서 데이터를 가저오는 비동기적 작업을 생성하였고, 아래 있는 코드 부분에 completionHandler에 해당하는 클로저다.
  4. ComletionHandler 클로저
    • CompletionHandler는 세개의 매개변수를 갖게 된다.
    • completionHandler: @escaping @Sendable (Data?, URLResponse?, (any Error)?) -> Void
    • Data? URLResponse? Error?
    • Data는 말그래도 서버에서 반환된 데이터를 말한다. URLResonpnse는 metadata 즉 헤더, status code, protocol 등등이 반환된다. Error는 Request fail한 경우 nil을 반환한다.
    • 해당 URL은 JSon 파일을 반환하기 떄문에, JSON 파일을 파싱하는 과정도 추가하였다.
    • JSONSerialization 는 JSON 데이터를 다루기 위한 Swift 내장 클래스이다.
    • JSONSerialization.jsonObject를 통해 데이터를 JSON Object로 생성하고, 옵션을 줄 수 있지만, 옵션의 대해서는 추후에 더 공부할 예정이다.
    • 이후에 데이터의 대한 파싱을 하여 print하는 것이다.
  5. Task.resume() 로 해당 task 실행
profile
개발자 (진)

0개의 댓글