본문 바로가기
YAGOM CAREER STARTER

[TIL] 20230411: URL Loading System

by Rhode 2023. 4. 14.

본문은 야곰 아카데미 커리어 스타터 캠프를 통해 학습한 내용을 회고한 글입니다.


URL Loading System

Overview

URL Loading System은 https와 같은 스탠다드 프로토콜 혹은 사용자가 만드는 커스텀 프로토콜을 사용하여 URL로 식별되는 리소스에 대한 접근을 제공한다. 로딩은 비동기적으로 수행되기 때문에, 앱이 응답성을 유지하고 데이터나 에러가 도착할 때 처리할 수 있다.

하나 혹은 그 이상의 URLSessionTask 인스턴스를 만들기 위해 URLSession 인스턴스를 사용하는데, 이 URLSessionTask는 데이터를 가져와서 앱으로 반환하고, 파일들을 다운로드하고, 혹은 데이터와 파일들을 원격 장소로 업로드할 수 있다. 세션을 구성하기 위해서는, 어떻게 캐시와 쿠키를 사용할지 혹은 셀룰러 네트워크에의 연결을 허용할지 말지 등의 행동을 컨트롤하는 URLSessionConfiguration 객체를 사용한다.

하나의 세션을 반복적으로 사용하여 작업을 생성할 수 있다. 예를 들어서, 어떤 웹 브라우저에는 일반 그리고 비공개 브라우징용으로 별도의 세션이 있을 수 있으며, 비공개 세션은 데이터를 캐시하지 않는다. Figure 1은 어떻게 이런 구성을 가진 두 개의 세션이 여러개의 작업을 생성할 수 있는지 보여준다.

Figure 1 Creating tasks from URL sessions

각각의 세션은 주기적인 업데이트(혹은 에러)를 수신하기 위해 델리게이트와 연결된다. 기본적인 델리게이트는 제공된 completion handler 블록을 호출한다; 만약 커스텀 델리게이트를 제공하고자한다면, 이 블록은 호출되지 않는다.

앱이 중단된 동안에, 시스템이 대신 데이터를 다운로드하고 앱을 깨워 결과를 전달할 수 있도록, 세션이 백그라운드에서 실행되도록 세션을 구성할 수 있다.



Fetching Website Data into Memory

Overview

remote 서버와 작은 상호작용의 경우, 응답 데이터를 메모리로 받아오기 위해서 URLSessionDataTask 클래스를 사용할 수 있다. (데이터를 직접적으로 파일 시스템에 저장하는 URLSessionDownloadTask 클래스를 사용하는 경우와 반대로) 데이터 작업은 웹 서비스 endpoint를 호출하는 것과 같은 용도에 이상적이다.

URL 세션 인스턴스를 사용해서 작업을 생성할 수 있다. 만약 요구사항이 간단하다면, URLSession 클래스의 shared 인스턴스를 사용할 수 있다. 만약 델리게이트 콜백을 통한 전송과 상호작용하려면, shared 인스턴스를 사용하는 대신에 세션 하나를 만들어야할 것이다. 세션을 만들 때는 URLSessionConfiguration 인스턴스를 사용한다. 또한 URLSessionDelegate나 하위 프로토콜 중 하나를 구현하는 클래스를 전달한다. 세션은 여러개의 작업을 생성하기 위해 재사용 될 수 있으므로, 필요한 각각의 고유 구성에 대해서, 세션을 생성하고 프로퍼티로 저장한다.

💡 필요한 것 이상으로 많은 세션을 만들지 않도록 주의하라. 예를 들어서, 앱의 여러부분에서 유사하게 구성된 세션을 필요로 하는 경우, 하나의 세션을 생성하여 공유한다.

세션이 있으면 dataTask() 메서드 중 하나를 이용하여 데이터 작업을 생성한다. 작업들은 일시 중단된 상태로 생성이 되며, resume()를 호출해서 시작할 수 있다.

Receive Results with Completion Handler

데이터를 받아오는 가장 간편한 방법은 completion handler를 사용하는 데이터 작업을 생성하는 것이다. 이러한 처리를 통해서, 그 작업은 서버의 response, data 그리고 error를 제공된 completion handler 블록에 넘겨준다. Figure 1은 세션과 작업과의 관계에 대해서 보여주고 있으며, 어떻게 결과가 completion handler에 전달되는지역시 보여주고 있다.

Figure 1 Creating a completion handler to receive results from a task

completion handler를 사용하는 데이터 작업을 생성하기 위해서는, URLSession의 dataTask(with:) 메서드를 사용하라. 그리고 completion handler는 다음의 세 가지 작업을 수행해야한다:

  1. error 매개변수가 nil이라는 것을 검증한다. 그렇지 않으면, error가 발생했다는 것을 전달한다; error를 처리하고 빠져나간다.
  2. status code가 성공을 가리키고 MIME type이 예상된 값이라는 것을 검증하기 위해서 response 매개변수를 확인한다. 그렇지 않다면, 서버 error를 처리하고 빠져나간다.
  3. 필요에 따라서 data 인스턴스를 사용한다.

Listing 1은 URL의 내용을 가져오는 startLoad() 메서드를 보여주고 있다. 이 과정은 결과값을 completion handler로 전달하는 데이터 작업을 만들기 위해 URLSession 클래스의 shared 인스턴스를 사용하는 것으로 시작한다. 로컬과 서버의 error를 확인한 후, 이 handler는 data를 String으로 변환한다, 그리고 그것을 WKWebView outlet을 생성하기 위해 사용한다. 당연하게도, 앱에서 가져온 데이터를 데이터 모델로 파싱하는 것과 같이 다른 용도로 사용할 수도 있다.

Listing 1 Creating a completion handler to receive data-loading results

func startLoad() {
    let url = URL(string: "https://www.example.com/")!
    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            self.handleClientError(error)
            return
        }
        guard let httpResponse = response as? HTTPURLResponse,
            (200...299).contains(httpResponse.statusCode) else {
            self.handleServerError(response)
            return
        }
        if let mimeType = httpResponse.mimeType, mimeType == "text/html",
            let data = data,
            let string = String(data: data, encoding: .utf8) {
            DispatchQueue.main.async {
                self.webView.loadHTMLString(string, baseURL: url)
            }
        }
    }
    task.resume()
}
 

💡 completion handler는 작업을 생성한 것과 다른 Grand Central Dispatch queue에서 호출된다. 그렇기때문에, UI를 업데이트하기 위해 data나 error를 사용하는 어떠한 작업이라도 (webView를 업데이트하는 것과 같은) 여기에 표시된 것처럼 명시적으로 main queue에 위치해야한다.