URLSession, Fetching Website Data into Memory

Groot·2022년 8월 24일
0

TIL

목록 보기
37/148
post-thumbnail

TIL

🌱 난 오늘 무엇을 공부했을까?

📌 URLSession 공식문서 정리

  • 관련된 네트워크 데이터 전송 작업 그룹을 조정하는 개체입니다.
class URLSession : NSObject
  • URLSession 클래스 및 관련 클래스는 URL로 표시된 엔드포인트에서 데이터를 다운로드하고 엔드포인트에 데이터를 업로드하기 위한 API를 제공합니다.
  • 또한 앱은 이 API를 사용하여 앱이 실행되고 있지 않거나 iOS에서 앱이 일시 중단된 동안 백그라운드 다운로드를 수행할 수 있습니다.
  • 관련 URLSessionDelegate 및 URLSessionTaskDelegate를 사용하여 인증을 지원하고 redirection 및 task completion.와 같은 이벤트를 수신할 수 있습니다.
  • 앱은 관련 데이터 전송 작업 그룹을 조정하는 각각의 URLSession 인스턴스를 하나 이상 만듭니다.
  • 예를 들어 웹 브라우저를 생성하는 경우 앱은 탭 또는 창당 하나의 세션을 생성하거나 대화형 사용을 위한 세션과 백그라운드 다운로드를 위한 세션을 생성할 수 있습니다.
  • 각 세션 내에서 앱은 일련의 작업을 추가하며, 각 작업은 특정 URL에 대한 요청을 나타냅니다(필요한 경우 HTTP 리디렉션을 따름).

📍 Types of URL Sessions

  • 주어진 URL 세션 내의 작업은 공통 세션 구성 개체를 공유합니다
  • 단일 호스트에 대한 최대 동시 연결 수, 연결이 셀룰러 네트워크를 사용할 수 있는지 여부 등과 같은 연결 동작을 정의합니다.
  • URLSession에는 기본 요청에 대한 단일 공유 세션(싱글톤?)이 있습니다.
  • 생성한 세션만큼 사용자 정의할 수는 없지만 요구 사항이 매우 제한적인 경우 좋은 출발점 역할을 합니다.
  • 공유 클래스 메서드를 호출하여 이 세션에 액세스합니다.
  • 다른 종류의 세션의 경우 다음 세 가지 구성 중 하나로 URLSession을 만듭니다.
    • default session은 공유 세션과 매우 유사합니다. 하지만 당신이 그것을 구성 할 수 있습니다. 데이터를 점진적으로 가져오기 위해 기본 세션에 대리자를 할당할 수도 있습니다.
    • Ephemeral sessions은 공유 세션과 유사하지만 캐시, 쿠키 또는 자격 증명을 디스크에 쓰지 않습니다.
    • Background sessions을 사용하면 앱이 실행되지 않는 동안 백그라운드에서 콘텐츠 업로드 및 다운로드를 수행할 수 있습니다.

📍 Types of URL Session Tasks

  • 세션 내에서 선택적으로 데이터를 서버에 업로드한 다음 디스크의 파일이나 메모리의 하나 이상의 NSData 개체로 서버에서 데이터를 검색하는 작업을 만듭니다.
  • URLSession API는 네 가지 유형의 작업을 제공합니다.
    • Data tasks는 NSData 개체를 사용하여 데이터를 보내고 받습니다. 데이터 작업은 서버에 대한 짧고 종종 대화형 요청을 위한 것입니다.
    • Upload tasks는 데이터 작업과 유사하지만 데이터(종종 파일 형식)를 보내고 앱이 실행되지 않는 동안 백그라운드 업로드를 지원합니다.
    • Download tasks는 파일 형식으로 데이터를 검색하고 앱이 실행되지 않는 동안 백그라운드 다운로드 및 업로드를 지원합니다.
    • WebSocket 작업은 RFC 6455에 정의된 WebSocket 프로토콜을 사용하여 TCP 및 TLS를 통해 메시지를 교환합니다.

Using a Session Delegate

  • 세션의 작업은 또한 공통 대리자 개체를 공유합니다.
  • 다양한 이벤트가 발생할 때 정보를 제공하고 얻기 위해 이 대리자를 구현합니다.
    • Authentication fails.
    • Data arrives from the server.
    • Data becomes available for caching.
  • 대리인이 제공하는 기능이 필요하지 않은 경우 세션을 생성할 때 nil을 전달하여 제공하지 않고 이 API를 사용할 수 있습니다.

    세션 개체는 앱이 종료되거나 세션을 명시적으로 무효화할 때까지 대리자에 대한 강력한 참조를 유지합니다. 세션을 무효화하지 않으면 앱이 종료될 때까지 앱에서 메모리가 누출됩니다.

  • 세션으로 생성한 각 작업은 URLSessionTaskDelegate에 정의된 메서드를 사용하여 세션의 대리자를 다시 호출합니다.
  • 작업에 특정한 별도의 대리자를 채워 세션 대리자에 도달하기 전에 이러한 콜백을 가로챌 수도 있습니다.

📍 Asynchronicity and URL Sessions

  • 대부분의 네트워킹 API와 마찬가지로 URLSession API는 고도로 비동기적입니다. 호출하는 메서드에 따라 다음 세 가지 방법 중 하나로 앱에 데이터를 반환합니다.
    • Swift를 사용하는 경우
      • async 키워드로 표시된 메서드를 사용하여 일반적인 작업을 수행할 수 있습니다.
      • 예를 들어 data(from:delegate:)는 데이터를 가져오는 반면 download(from:delegate:)는 파일을 다운로드합니다.
      • 콜 포인트는 await 키워드를 사용하여 전송이 완료될 때까지 실행을 일시 중단합니다. 또한 bytes(from:delegate:) 메서드를 사용하여 AsyncSequence로 데이터를 받을 수 있습니다.
      • 이 접근 방식에서는 for-wait-in 구문을 사용하여 앱이 데이터를 수신할 때 데이터를 반복합니다. URL 유형은 공유 URL 세션에서 바이트 또는 줄을 가져오는 편리한 방법도 제공합니다.
    • Swift 또는 Objective-C에서는 전송이 완료될 때 실행되는 완료 핸들러 블록을 제공할 수 있습니다.
    • Swift 또는 Objective-C에서는 전송이 진행되고 완료된 직후 대리자 메서드에 대한 콜백을 받을 수 있습니다.
  • 이 정보를 대리인에게 전달하는 것 외에도 URLSession은 상태 및 진행률 속성을 제공합니다.
  • 작업의 현재 상태를 기반으로 프로그래밍 방식의 결정을 내려야 하는 경우 이러한 속성을 쿼리합니다(해당 상태는 언제든지 변경될 수 있다는 경고 포함).

📍 Protocol Support

  • URLSession 클래스는 기본적으로 사용자의 시스템 기본 설정에 구성된 대로 프록시 서버 및 SOCKS 게이트웨이에 대한 투명한 지원과 함께 데이터, 파일, ftp, http 및 https URL 체계를 지원합니다.
  • URLSession은 HTTP/1.1, HTTP/2 및 HTTP/3 프로토콜을 지원합니다. RFC 7540에 설명된 대로 HTTP/2 지원에는 ALPN(응용 계층 프로토콜 협상)을 지원하는 서버가 필요합니다.
  • 또한 URLProtocol을 서브클래싱하여 고유한 사용자 지정 네트워킹 프로토콜 및 URL 체계(앱의 개인용)에 대한 지원을 추가할 수 있습니다.

📍 App Transport Security (ATS)

  • iOS 9.0 및 macOS 10.11 이상은 URLSession으로 이루어진 모든 HTTP 연결에 앱 전송 보안(ATS)을 사용합니다.
  • ATS를 사용하려면 HTTP 연결에서 HTTPS(RFC 2818)를 사용해야 합니다.

📍 Foundation Copying Behavior

  • 세션 및 작업 개체는 다음과 같이 NSCopying 프로토콜을 따릅니다.
    • 앱이 세션 또는 작업 개체를 복사하면 동일한 개체를 다시 가져옵니다.
    • 앱이 구성 개체를 복사하면 독립적으로 수정할 수 있는 새 복사본이 생성됩니다.

📍 Thread Safety

  • URL 세션 API는 스레드로부터 안전합니다.
  • 모든 스레드 컨텍스트에서 세션과 작업을 자유롭게 생성할 수 있습니다.
  • 대리자 메서드가 제공된 완료 처리기를 호출하면 작업이 올바른 대리자 대기열에 자동으로 예약됩니다.

URLSession공식문서


📌 Fetching Website Data into Memory 공식문서 정리

  • URL 세션에서 데이터 작업을 생성하여 데이터를 메모리로 직접 수신합니다.

📍 Overview

  • 원격 서버와의 소규모 상호 작용의 경우 URLSessionDataTask 클래스를 사용하여 응답 데이터를 메모리로 수신할 수 있습니다(데이터를 파일 시스템에 직접 저장하는 URLSessionDownloadTask 클래스를 사용하는 것과는 반대).
  • 데이터 작업은 web service endpoint 호출과 같은 용도에 이상적입니다.
  • URL 세션 인스턴스를 사용하여 작업을 만듭니다.
  • 요구 사항이 매우 간단하다면 URLSession 클래스의 공유 인스턴스를 사용할 수 있습니다.
  • 대리자 콜백을 통해 전송과 상호 작용하려면 공유 인스턴스를 사용하는 대신 세션을 만들어야 합니다.
  • 세션을 생성할 때 URLSessionConfiguration 인스턴스를 사용하고 URLSessionDelegate 또는 하위 프로토콜 중 하나를 구현하는 클래스도 전달합니다.
  • 세션을 재사용하여 여러 작업을 생성할 수 있으므로 필요한 각각의 고유한 구성에 대해 세션을 생성하고 속성으로 저장합니다.

    필요한 것보다 더 많은 세션을 생성하지 않도록 주의하십시오. 예를 들어, 유사하게 구성된 세션이 필요한 앱의 여러 부분이 있는 경우 하나의 세션을 만들고 공유하십시오.

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

📍 Receive Results with a Completion Handler

  • 데이터를 가져오는 가장 간단한 방법은 completion handler를 사용하는 데이터 작업을 만드는 것입니다.
  • 이 배열을 통해 작업은 서버의 응답, 데이터 및 가능한 오류를 사용자가 제공한 완료 처리기 블록으로 전달합니다.
  • 다음 그림은 세션과 작업 간의 관계와 결과가 완료 처리기에 전달되는 방식을 보여줍니다.
  • 완료 핸들러를 사용하는 데이터 태스크를 생성하려면 URLSession의 dataTask(with:) 메소드를 호출하십시오. 완료 핸들러는 다음 세 가지 작업을 수행해야 합니다.
    • 오류 매개변수가 nil인지 확인하십시오. 그렇지 않은 경우 전송 오류가 발생한 것입니다. 오류를 처리하고 종료합니다.
    • 응답 매개변수를 확인하여 상태 코드가 성공을 나타내고 MIME 유형이 예상 값인지 확인하십시오. 그렇지 않은 경우 서버 오류를 처리하고 종료합니다.
    • 필요에 따라 데이터 인스턴스를 사용합니다.
  • 다음은 URL의 내용을 가져오기 위한 startLoad() 메소드를 보여줍니다.
  • URLSession 클래스의 공유 인스턴스를 사용하여 결과를 completion handler에 전달하는 데이터 작업을 만드는 것으로 시작합니다.
  • 로컬 및 서버 오류를 확인한 후 이 핸들러는 데이터를 문자열로 변환하고 WKWebView 콘센트를 채우는 데 사용합니다.
  • 물론 앱에서 가져온 데이터를 데이터 모델로 구문 분석하는 것과 같이 다른 용도로 사용할 수도 있습니다.
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()
}

완료 핸들러는 작업을 생성한 것과 다른 Grand Central Dispatch 대기열에서 호출됩니다. 따라서 webView 업데이트와 같이 UI를 업데이트하기 위해 데이터나 오류를 사용하는 모든 작업은 여기에 표시된 것처럼 명시적으로 기본 대기열에 배치되어야 합니다.

📍 Receive Transfer Details and Results with a Delegate

  • 작업이 진행됨에 따라 작업 활동에 대한 더 높은 수준의 액세스를 위해 데이터 작업을 생성할 때 완료 핸들러를 제공하는 대신 세션에 대리자를 설정할 수 있습니다.
  • 이 접근 방식을 사용하면 데이터의 일부가 도착하면 전송이 완료되거나 오류와 함께 실패할 때까지 URLSessionDataDelegate의 urlSession(_:dataTask:didReceive:) 메서드에 제공됩니다.
  • 대리자는 전송이 진행됨에 따라 다른 종류의 이벤트도 수신합니다.
  • URLSession 클래스의 간단한 공유 인스턴스를 사용하는 대신 대리자 접근 방식을 사용할 때 고유한 URLSession 인스턴스를 만들어야 합니다.
  • 새 세션을 생성하면 아래와 같이 자신의 클래스를 세션의 대리자로 설정할 수 있습니다.
  • 클래스가 대리자 프로토콜(URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate 및 URLSessionDownloadDelegate) 중 하나 이상을 구현한다고 선언합니다.
  • 그런 다음 초기화 프로그램 init(configuration:delegate:delegateQueue:)를 사용하여 URL 세션 인스턴스를 만듭니다.
  • 이 이니셜라이저와 함께 사용되는 구성 인스턴스를 사용자 정의할 수 있습니다.
private lazy var session: URLSession = {
    let configuration = URLSessionConfiguration.default
    configuration.waitsForConnectivity = true
    return URLSession(configuration: configuration,
                      delegate: self, delegateQueue: nil)
}()
  • 아래의 코드는 이 세션을 사용하여 데이터 작업을 시작하고 대리자 콜백을 사용하여 수신된 데이터 및 오류를 처리하는 startLoad() 메서드를 보여줍니다.
  • 이 목록은 세 가지 대리자 콜백을 구현합니다
    • urlSession(_:dataTask:didReceive:completionHandler:)은 응답에 성공적인 HTTP 상태 코드가 있고 MIME 유형이 text/html 또는 text/plain인지 확인합니다. 둘 중 하나라도 해당되지 않으면 작업이 취소됩니다. 그렇지 않으면 계속 진행할 수 있습니다.
    • urlSession(_:dataTask:didReceive:)은 태스크가 수신한 각 Data 인스턴스를 받아 수신 데이터라는 버퍼에 추가합니다.
    • urlSession(_:task:didCompleteWithError:)은 먼저 전송 수준 오류가 발생했는지 확인합니다. 오류가 없으면 수신된 데이터 버퍼를 문자열로 변환하여 webView의 내용으로 설정을 시도한다.
var receivedData: Data?

func startLoad() {
    loadButton.isEnabled = false
    let url = URL(string: "https://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 {
        completionHandler(.cancel)
        return
    }
    completionHandler(.allow)
}

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

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    DispatchQueue.main.async {
        self.loadButton.isEnabled = true
        if let error = error {
            handleClientError(error)
        } else if let receivedData = self.receivedData,
            let string = String(data: receivedData, encoding: .utf8) {
            self.webView.loadHTMLString(string, baseURL: task.currentRequest?.url)
        }
    }
}
  • 다양한 대리자 프로토콜은 인증 문제 처리, 리디렉션 및 기타 특수한 경우를 처리하기 위해 위의 코드에 표시된 것 이외의 방법을 제공합니다.
  • URL 세션 토론에서 URL 세션 사용은 전송 중에 발생할 수 있는 다양한 콜백에 대해 설명합니다.

Fetching Website Data into Memory공식문서

profile
I Am Groot

0개의 댓글