[번역] Fetching website data into memory (애플 공식 문서)

삭제된 Velog·2024년 10월 10일

Foundation

목록 보기
1/2
post-thumbnail

본 글은 Fetching website data into memory (애플 공식 문서)를 한국어로 번역하여 옮긴 글입니다.

URL 세션에서 데이터 작업(data task)을 만들어 데이터를 바로 메모리로 수신하세요.


Overview

원격 서버와 가벼운 상호 작용을 하려면 URLSessionDataTask 클래스를 사용하여 응답 데이터를 메모리로 수신하세요. (이와 반대로 데이터를 곧장 파일 시스템에 저장하려면 URLSessionDownloadDataTask 클래스를 사용하세요) 데이터 작업은 웹 서비스 엔드 포인트(endpoint)를 호출하는 용도로 적합합니다.

작업을 생성하려면 URL 세션 인스턴스를 사용하세요. 요구 사항이 꽤 간단하다면, URLSession 클래스의 shared 인스턴스를 사용할 수 있습니다. 델리게이트 콜백(delegate callback)으로 전송과 상호작용하기 원한다면 shared 인스턴스를 사용하는 대신 직접 세션을 만들어야 합니다. 세션을 생성할 때 URLSessionConfiguration 인스턴스를 사용하고, URLSessionDelegate나 그것의 하위 프로토콜 중 하나를 구현하는 클래스를 전달하세요. 세션은 다양한 작업을 생성하기 위해 재사용될 수 있으며, 필요로 하는 고유한 구성(configuration)마다 세션을 생성하고 프로퍼티에 저장해야 합니다.

⚪️ Note
필요보다 더 많은 세션을 생성하지 않도록 주의하세요. 예를 들어, 앱의 여러 부분에서 비슷한 구성의 세션을 필요로 한다면, 세션을 하나만 생성하고 서로 공유하세요.

세션을 생성한 후에는 dataTask() 메서드 중 하나를 사용하여 데이터 작업을 생성하세요. 작업은 중지된 상태로 생성되며, resume() 메서드를 호출하여 시작될 수 있습니다.

Receive results with a completion handler

데이터를 가져오는 가장 쉬운 방법은 컴플리션 핸들러(completion handler)를 사용하는 데이터 작업을 생성하는 것입니다. 이 방식으로 작업은 서버의 응답, 데이터와 발생할 수 있는 오류를 제공된 컴플리션 핸들러 블록에 전달합니다. 아래 그림은 세션과 작업 사이 관계를 보여주고, 어떻게 결과를 컴플리션 핸들러에 전달하는지 보여줍니다.

컴플리션 핸들러를 사용하는 데이터 작업을 생성하려면, URLSessiondataTask(with:) 메서드를 호출하세요. 컴플리션 핸들러는 아래 3가지 작업을 수행해야 합니다.

  1. erorr 매개변수가 nil인지 확인하세요. nil이 아니라면, 전송 오류가 발생한 것이므로 오류를 처리하고 종료하세요.

  2. response 매개변수로 상태 코드가 성공을 나타내고 MIME 타입이 예상된 값인지 확인하세요. 그렇지 않다면, 서버 오류를 처리하고 종료하세요.

  3. 필요하다면 data 인스턴스를 사용하세요.

Listing 1은 URL의 컨텐츠를 가져오는 startLoad() 메서드를 보여줍니다. 컴플리션 핸들러에 결과를 전달하는 데이터 작업을 생성하고자 URLSessionshared 인스턴스를 사용합니다. 로컬과 서버 오류를 검사하고 난 후, 이 핸들러는 데이터를 문자열로 변환하고 이를 사용하여 WKWebView 아웃렛에 데이터를 로드합니다. 물론, 가져온 데이터를 데이터 모델로 파싱(parsing)하는 등 다른 용도로 사용할 수 있습니다.

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? HTTPResponse,
        	  (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()
}

🟡 Important
컴플리션 핸들러는 작업을 생성한 것과 다른 Grand Central Dispatch 큐에서 호출됩니다. 그러므로, webView를 업데이트한 것처럼 데이터나 오류를 사용하여 UI를 업데이트하는 작업은 명시적으로 메인 큐에 배치해야 합니다.

Receive transfer details and results with a delegate

작업이 진행되는 동안 컴플리션 핸들러보다 더 높은 수준의 접근이 필요하다면, 데이터 작업을 만들 때 세션에 델리게이트를 설정할 수 있습니다. 아래 그림은 이 방식을 보여줍니다.

이러한 접근으로, 데이터의 일부를 수신할 때마다 URLSessionDataDelegateurlSession(_:dataTask:didReceive:) 메서드가 호출되며, 전송이 끝나거나 오류로 실패할 때까지 반복됩니다. 델리게이트는 전송이 진행되는 동안 다른 종류의 이벤트도 수신합니다.

델리게이트 접근을 사용할 때는 URLSession의 간단한 shared 인스턴스를 사용하는 것보다 직접 URLSession 인스턴스를 생성할 필요가 있습니다. Listing 2에서 보다시피, 직접 정의한 클래스를 새로운 세션의 델리게이트로 설정할 수 있습니다.

하나 이상의 프로토콜(URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegateURLSessionDownloadDelegate)을 구현하는 클래스를 선언하세요. 그리고 init(configuration:delegate:delegateQueue:) 이니셜라이저로 URLSession 인스턴스를 생성하세요. 이 이니셜라이저를 사용하여 구성 인스턴스를 사용자화할 수 있습니다. 예를 들어, waitsForConnectivity 프로퍼티를 true로 설정해보세요. 이렇게 하여, 세션은 필요한 연결이 없으면 곧바로 실패하기 보다, 적절한 연결을 기다립니다.

private lazy var session: URLSession = {
	let configuration = URLSessionConfiguration.default
    configuration.waitsForConnectivity = true
    return URLSession(configuration: configuration,
    				  delegate: self, delegateQueue: nil)
}()

Listing 3는 이 세션을 사용하여 데이터 작업을 시작하는 startLoad() 메서드와 수신한 데이터와 오류를 처리하고자 델리게이트 콜백을 사용하는 모습을 보여줍니다. 아래 예제는 3가지 델리게이트 콜백을 구현합니다.

  • urlSession(_:dataTask:didReceive:completionHandler:) 메서드는 응답이 성공적인 HTTP 상태 코드를 가지며, MIME 타입이 text/html이나 text/plain인지 확인합니다. 어느 조건도 충족하지 못하면 해당 작업은 취소되고, 그렇지 않으면 작업은 계속 진행됩니다.

  • urlSession(_:dataTask:didReceive:) 메서드는 작업에 의해 수신하는 각 Data 인스턴스를 receivedData라 불리는 버퍼에 추가합니다.

  • urlSession=(_:task:didCompleteWithError:) 메서드는 먼저 전송 단계에서 오류가 발생했는지 살펴봅니다. 오류가 없다면 receivedData 버퍼를 문자열로 변환을 시도하고 webView의 컨텐츠로 설정합니다.

var receivedData: Data?

func startLoad() {
	loadButton.isEnabled = false
    let url = URL(string: "htttps://www.example.com/")!
    receivedData = Data()
    let task = session.dataTask(with: url)
    task.resume()
}

// delegate methods

func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse,
				completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
	guard let response = response as? HTTPURLResponse,
    	(200...299).contains(response.statusCode),
        let mimeType = response.mimeType,
        mimeType == "text/html" else {
    	return
    }
    completionHandler(.allow)
}

func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceived data: Data) {
	self.receivedData?.append(data)
}

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Erorr?) {
	DispatchQueue.main.async {
    	self.loadButton.isEnabled = true
        if let error = error {
        	handldClilentError(error)
        } else if let receivedData = self.receivedData {
        	let string = String(data: receivedData, encoding: .utf8)
            self.webView.loadHTMLString(string, baseURL: task.currentResponse?.url)
        }
    }
}

다양한 델리게이트 프로토콜은 상단 예제에서 보여준 걸 넘어 인증 요구 처리, 리다이렉트 추적, 기타 특수 사례를 처리하기 위한 메서드들도 제공합니다. URL 세션 사용은 URLSession에서 설명한 바와 같이 전송 중 발생하는 다양한 콜백을 설명합니다.

참고 자료

profile
rlarjsdn3.github.io

0개의 댓글